// Simple IPv4 Link-Local addressing (see ) // @(#)llip.c, 1.5, Copyright 2003 by Arthur van Hoff ([email protected]) // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // See // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LINKLOCAL_ADDR 0xa9fe0000 #define LINKLOCAL_MASK 0xFFFF0000 #define NPROBES 3 #define PROBE_INTERVAL 200 #define NCLAIMS 3 #define CLAIM_INTERVAL 200 #define FAILURE_INTERVAL 14000 #define DEFAULT_INTERFACE "eth0" #define DEFAULT_SCRIPT "/etc/network.script" static char *prog; #ifdef DEBUG static int verbose = 0; #endif static struct in_addr null_ip = {0}; static struct ether_addr null_addr = {{0, 0, 0, 0, 0, 0}}; static struct ether_addr broadcast_addr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; /** * ARP packet. */ struct arp_packet { struct ether_header hdr; struct arphdr arp; struct ether_addr source_addr; struct in_addr source_ip; struct ether_addr target_addr; struct in_addr target_ip; unsigned char pad[18]; } __attribute__ ((__packed__)); #ifdef DEBUG /** * Convert an ethernet address to a printable string. */ static char *ether2str(const struct ether_addr *addr) { static char str[32]; snprintf(str, sizeof(str), "%02X:%02X:%02X:%02X:%02X:%02X", addr->ether_addr_octet[0], addr->ether_addr_octet[1], addr->ether_addr_octet[2], addr->ether_addr_octet[3], addr->ether_addr_octet[4], addr->ether_addr_octet[5]); return str; } #endif /** * Pick a random link local IP address. */ static void pick(struct in_addr *ip) { ip->s_addr = htonl(LINKLOCAL_ADDR | ((abs(random()) % 0xFD00) + 0x0100)); } /** * Send out an ARP packet. */ static void arp(int fd, struct sockaddr *saddr, int op, struct ether_addr *source_addr, struct in_addr source_ip, struct ether_addr *target_addr, struct in_addr target_ip) { struct arp_packet p; memset(&p, 0, sizeof(p)); // ether header p.hdr.ether_type = htons(ETHERTYPE_ARP); memcpy(p.hdr.ether_shost, source_addr, ETH_ALEN); memcpy(p.hdr.ether_dhost, &broadcast_addr, ETH_ALEN); // arp request p.arp.ar_hrd = htons(ARPHRD_ETHER); p.arp.ar_pro = htons(ETHERTYPE_IP); p.arp.ar_hln = ETH_ALEN; p.arp.ar_pln = 4; p.arp.ar_op = htons(op); memcpy(&p.source_addr, source_addr, ETH_ALEN); memcpy(&p.source_ip, &source_ip, sizeof(p.source_ip)); memcpy(&p.target_addr, target_addr, ETH_ALEN); memcpy(&p.target_ip, &target_ip, sizeof(p.target_ip)); // send it if (sendto(fd, &p, sizeof(p), 0, saddr, sizeof(*saddr)) < 0) { perror("sendto failed"); exit(1); } } /** * Run a script. */ void run(char *script, char *arg, char *intf, struct in_addr *ip) { int pid, status; if (script != NULL) { #ifdef DEBUG if (verbose) { fprintf(stderr, "%s %s: run %s %s\n", prog, intf, script, arg); } #endif pid = fork(); if (pid < 0) { perror("fork failed"); exit(1); } if (pid == 0) { // child process setenv("interface", intf, 1); if (ip != NULL) { setenv("ip", inet_ntoa(*ip), 1); } execl(script, script, arg, NULL); perror("execl failed"); exit(1); } if (waitpid(pid, &status, 0) <= 0) { perror("waitpid failed"); exit(1); } if (WEXITSTATUS(status) != 0) { fprintf(stderr, "%s: script %s failed, exit=%d\n", prog, script, WEXITSTATUS(status)); exit(1); } } } /** * Print usage information. */ static void usage(char *msg) { fprintf(stderr, "%s: %s\n\n", prog, msg); fprintf(stderr, "Usage: %s [OPTIONS\n"); #ifdef DEBUG fprintf(stderr, " -v verbose\n"); #endif fprintf(stderr, " -q quit after obtaining address\n"); fprintf(stderr, " -f do not fork a daemon\n"); fprintf(stderr, " -n exit with failure if no address can be obtained\n"); fprintf(stderr, " -i network interface (default %s)\n", DEFAULT_INTERFACE); fprintf(stderr, " -s