// 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