Re: AW: Add new target in mangle table

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



-------- Original-Nachricht --------
> Datum: Tue, 15 Apr 2008 11:52:06 +0200 (CEST)
> Von: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>
> An: manuel scheub <manuprivat@xxxxxx>
> CC: netfilter-devel@xxxxxxxxxxxxxxx
> Betreff: Re: AW: Add new target in mangle table

> 
> On Tuesday 2008-04-15 11:20, manuel scheub wrote:
> >> >
> >> >I modified the udhcpd from the busybox  - have a look in the attached
> >> >file.
> >> >To handle the different cases i wrote a shell script - also attached.
> >> 
> >> But if the client uses DHCP, why don't you hand out 10.0.x.x directly?
> >
> >If the client uses DHCP, i do hand out 10.0.x.x directly! The
> >modified dhcpd listens on all requests, it doesn't matter if it is
> >not a dhcp-request.
> 
> But there is only DHCPINFORM which might carry a non 10.0.x.x
> address.
> I think it's simpler if you just add 192.168.0.0/16 as an
> address to eth0.

There are some more modifications in the source code for the udhcp stuff in busybox. I think I didn't give you the correct information about the ip-plug'n'play with the dhcpd.c file. I've attached some more files, the main point is in the arpping.c. I've also attatched the file ippnpadd with the filter rules (there is also a file ippnpremove).
If I add 192.168.0.0/16, I didn't get the users with fix ip entries 10.120.0.1, 172.123.1.0,... maybe some business guys have these ip's.


-- 
Der GMX SmartSurfer hilft bis zu 70% Ihrer Onlinekosten zu sparen! 
Ideal für Modem und ISDN: http://www.gmx.net/de/go/smartsurfer
/*
 * arpping.c
 *
 * Mostly stolen from: dhcpcd - DHCP client daemon
 * by Yoichi Hariguchi <yoichi@xxxxxxxx>
 */

#include <sys/time.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "dhcpd.h"
#include "arpping.h"
#include "common.h"
#include "options.h"

/* args:	yiaddr - what IP to ping
 *		ip - our ip
 *		mac - our arp address
 *		interface - interface to use
 * retn: 	1 addr free
 *		0 addr used
 *		-1 error 
 */  

/* FIXME: match response against chaddr */
int arpping(uint32_t yiaddr, uint32_t ip, uint8_t *mac, char *interface)
{

	int	timeout = 2;
	int 	optval = 1;
	int	s;			/* socket */
	int	rv = 1;			/* return value */
	struct sockaddr addr;		/* for interface name */
	struct arpMsg	arp;
	fd_set		fdset;
	struct timeval	tm;
	time_t		prevTime;


	if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) {
#ifdef IN_BUSYBOX
		LOG(LOG_ERR, bb_msg_can_not_create_raw_socket);
#else
		LOG(LOG_ERR, "Could not open raw socket");
#endif
		return -1;
	}
	
	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
		LOG(LOG_ERR, "Could not setsocketopt on raw socket");
		close(s);
		return -1;
	}

	/* send arp request */
	memset(&arp, 0, sizeof(arp));
	memcpy(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6);	/* MAC DA */
	memcpy(arp.ethhdr.h_source, mac, 6);		/* MAC SA */
	arp.ethhdr.h_proto = htons(ETH_P_ARP);		/* protocol type (Ethernet) */
	arp.htype = htons(ARPHRD_ETHER);		/* hardware type */
	arp.ptype = htons(ETH_P_IP);			/* protocol type (ARP message) */
	arp.hlen = 6;					/* hardware address length */
	arp.plen = 4;					/* protocol address length */
	arp.operation = htons(ARPOP_REQUEST);		/* ARP op code */
	memcpy(arp.sInaddr, &ip, sizeof(ip));		/* source IP address */
	memcpy(arp.sHaddr, mac, 6);			/* source hardware address */
	memcpy(arp.tInaddr, &yiaddr, sizeof(yiaddr));	/* target IP address */
	
	memset(&addr, 0, sizeof(addr));
	strcpy(addr.sa_data, interface);
	if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
		rv = 0;
	
	/* wait arp reply, and check it */
	tm.tv_usec = 0;
	time(&prevTime);
	while (timeout > 0) {
		FD_ZERO(&fdset);
		FD_SET(s, &fdset);
		tm.tv_sec = timeout;
		if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) {
			DEBUG(LOG_ERR, "Error on ARPING request: %m");
			if (errno != EINTR) rv = 0;
		} else if (FD_ISSET(s, &fdset)) {
			if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0;
			if (arp.operation == htons(ARPOP_REPLY) && 
			    bcmp(arp.tHaddr, mac, 6) == 0 && 
			    *((uint32_t *) arp.sInaddr) == yiaddr) {
				DEBUG(LOG_INFO, "Valid arp reply receved for this address");
				rv = 0;
				break;
			}
		}
		timeout -= time(NULL) - prevTime;
		time(&prevTime);
	}
	close(s);
	DEBUG(LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V");	 
	return rv;
}

struct arpPacket {
        uint16_t htype;                         /* hardware type (must be ARPHRD_ETHER) */
        uint16_t ptype;                         /* protocol type (must be ETH_P_IP) */
        uint8_t  hlen;                          /* hardware address length (must be 6) */
        uint8_t  plen;                          /* protocol address length (must be 4) */
        uint16_t operation;                     /* ARP opcode */
        uint8_t  sHaddr[6];                     /* sender's hardware address */
        uint8_t  sInaddr[4];                    /* sender's IP address */
        uint8_t  tHaddr[6];                     /* target's hardware address */
        uint8_t  tInaddr[4];                    /* target's IP address */
        uint8_t  pad[18];                       /* pad for min. Ethernet payload (60 bytes) */
};

void handleArpRequest(unsigned char *mac, uint32_t ip)
{
	uint32_t freeaddr = 0;

	struct dhcpOfferedAddr *lease = find_lease_by_chaddr(mac);
	if (lease) {
		char buf[256];

		if (lease->ippnpaddr == ip) {
			if (!lease_expired(lease)) {
				lease->expires = time(0) + server_config.lease;
				DEBUG(LOG_INFO, "handleArpRequest: ip-addresses match");
				return;
			}
			DEBUG(LOG_INFO, "handleArpRequest: ip-addresses match but expired");
		}
		else if (!lease_expired(lease)) {
			if (ip == lease->yiaddr) {
				DEBUG(LOG_INFO, "handleArpRequest: assume dhcp lease");
				return;
			}
		}

		DEBUG(LOG_INFO, "handleArpRequest: ip-addresses differ %08X %08X", lease->ippnpaddr, ip);
		sprintf(buf, "ippnpremove %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s", 
			lease->chaddr[0], lease->chaddr[1], lease->chaddr[2],
			lease->chaddr[3], lease->chaddr[4], lease->chaddr[5],
			(lease->yiaddr) & 0xff, (lease->yiaddr >> 8) & 0xff,
			(lease->yiaddr >> 16) & 0xff, (lease->yiaddr >> 24) & 0xff,
			lease->ifname);
		DEBUG(LOG_INFO, "Exec %s", buf);
		system(buf);
		freeaddr = lease->yiaddr;
		clear_lease(lease->chaddr, lease->yiaddr);
	}
	else
		freeaddr = find_address(0);

	if (!freeaddr)
		freeaddr = find_address(1);

	if (freeaddr) {
		struct option_set *o = find_option(server_config.options, DHCP_ROUTER);

		add_lease(mac, freeaddr, server_config.offer_time, ip, server_config.ifname[server_config.currentinterface]);
		if (o) {
			uint32_t gaddr;
			uint32_t extip1 = ip;
			unsigned char *pgaddr = (char *) &gaddr;
			unsigned char *pintip = (char *) &freeaddr;
			unsigned char *pextip = (char *) &ip;
			unsigned char *pextip1 = (char *) &extip1;
			char command[256];

			memcpy(&gaddr, &o->data[2], 4);

			if (server_config.offset != 1) {
				int leasenumber = (ntohl(freeaddr) - ntohl(server_config.start)) / server_config.offset;

				gaddr = ntohl(gaddr);
				gaddr += (server_config.offset * leasenumber);
				gaddr = htonl(gaddr);
			}
			if (pextip1[3] == 1)
				pextip1[3]++;
			else
				pextip1[3]--;

			sprintf(command, "ippnpadd %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d %s",
				mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
				pgaddr[0], pgaddr[1], pgaddr[2], pgaddr[3],
				pintip[0], pintip[1], pintip[2], pintip[3],
				pextip[0], pextip[1], pextip[2], pextip[3],
				pextip1[0], pextip1[1], pextip1[2], pextip1[3],
				server_config.ifname[server_config.currentinterface]);
			DEBUG(LOG_INFO, "Exec %s", command);
			system(command);
		}
	}
}


int handleArpPacket(uint8_t *a)
{
	struct arpPacket *arp = (struct arpPacket *) a;
	DEBUG(LOG_INFO, "%d %d %d %d %d\n", arp->htype, arp->ptype, arp->hlen, arp->plen, ntohs(arp->operation));
	DEBUG(LOG_INFO, "%02x:%02x:%02x:%02x:%02x:%02x %d.%d.%d.%d %02x:%02x:%02x:%02x:%02x:%02x %d.%d.%d.%d\n",
		arp->sHaddr[0], arp->sHaddr[1], arp->sHaddr[2], arp->sHaddr[3], arp->sHaddr[4], arp->sHaddr[5],
		arp->sInaddr[0], arp->sInaddr[1], arp->sInaddr[2], arp->sInaddr[3],
		arp->tHaddr[0], arp->tHaddr[1], arp->tHaddr[2], arp->tHaddr[3], arp->tHaddr[4], arp->tHaddr[5],
		arp->tInaddr[0], arp->tInaddr[1], arp->tInaddr[2], arp->tInaddr[3]
	);
	if (ntohs(arp->operation) == 1 && memcmp(server_config.arp[server_config.currentinterface], arp->sHaddr, 6) != 0) {
                uint32_t ip;
		unsigned char chaddr[16];

		memset(chaddr, 0, 16);
		memcpy(chaddr, arp->sHaddr, 6);
		memcpy(&ip, arp->sInaddr, 4);

                handleArpRequest(chaddr, ip);
	}
	return 0;
}
/* 
 * files.c -- DHCP server file manipulation *
 * Rewrite by Russ Dill <Russ.Dill@xxxxxxx> July 2001
 */
 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <netdb.h>

#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "common.h"

/* 
 * Domain names may have 254 chars, and string options can be 254
 * chars long. However, 80 bytes will be enough for most, and won't
 * hog up memory. If you have a special application, change it
 */
#define READ_CONFIG_BUF_SIZE 16384

/* on these functions, make sure you datatype matches */
static int read_ip(const char *line, void *arg)
{
	struct in_addr *addr = arg;
	struct hostent *host;
	int retval = 1;

	if (!inet_aton(line, addr)) {
		if ((host = gethostbyname(line))) 
			addr->s_addr = *((unsigned long *) host->h_addr_list[0]);
		else retval = 0;
	}
	return retval;
}


static int read_str(const char *line, void *arg)
{
	char **dest = arg;
	
	if (*dest) free(*dest);
	*dest = strdup(line);
	
	return 1;
}


static int read_u32(const char *line, void *arg)
{
	uint32_t *dest = arg;
	char *endptr;
	*dest = strtoul(line, &endptr, 0);
	return endptr[0] == '\0';
}


static int read_yn(const char *line, void *arg)
{
	char *dest = arg;
	int retval = 1;

	if (!strcasecmp("yes", line))
		*dest = 1;
	else if (!strcasecmp("no", line))
		*dest = 0;
	else retval = 0;
	
	return retval;
}


/* read a dhcp option and add it to opt_list */
static int read_opt(const char *const_line, void *arg)
{
	struct option_set **opt_list = arg;
	char *opt, *val, *endptr;
	struct dhcp_option *option;
	int retval = 0, length;
	char buffer[8];
	char *line;
	uint16_t *result_u16 = (uint16_t *) buffer;
	uint32_t *result_u32 = (uint32_t *) buffer;

	/* Cheat, the only const line we'll actually get is "" */
	line = (char *) const_line;
	if (!(opt = strtok(line, " \t="))) return 0;
	
	for (option = dhcp_options; option->code; option++)
		if (!strcasecmp(option->name, opt))
			break;
	
	if (!option->code) return 0;

	do {
		if (!(val = strtok(NULL, ", \t"))) break;
		length = option_lengths[option->flags & TYPE_MASK];
		retval = 0;
		opt = buffer; /* new meaning for variable opt */
		switch (option->flags & TYPE_MASK) {
		case OPTION_IP:
			retval = read_ip(val, buffer);
			break;
		case OPTION_IP_PAIR:
			retval = read_ip(val, buffer);
			if (!(val = strtok(NULL, ", \t/-"))) retval = 0;
			if (retval) retval = read_ip(val, buffer + 4);
			break;
		case OPTION_STRING:
			length = strlen(val);
			if (length > 0) {
				if (length > 254) length = 254;
				opt = val;
				retval = 1;
			}
			break;
		case OPTION_BOOLEAN:
			retval = read_yn(val, buffer);
			break;
		case OPTION_U8:
			buffer[0] = strtoul(val, &endptr, 0);
			retval = (endptr[0] == '\0');
			break;
		case OPTION_U16:
			*result_u16 = htons(strtoul(val, &endptr, 0));
			retval = (endptr[0] == '\0');
			break;
		case OPTION_S16:
			*result_u16 = htons(strtol(val, &endptr, 0));
			retval = (endptr[0] == '\0');
			break;
		case OPTION_U32:
			*result_u32 = htonl(strtoul(val, &endptr, 0));	
			retval = (endptr[0] == '\0');
			break;
		case OPTION_S32:
			*result_u32 = htonl(strtol(val, &endptr, 0));	
			retval = (endptr[0] == '\0');
			break;
		default:
			break;
		}
		if (retval) 
			attach_option(opt_list, option, opt, length);
	} while (retval && option->flags & OPTION_LIST);
	return retval;
}


static const struct config_keyword keywords[] = {
	/* keyword	handler   variable address		default */
	{"start",	read_ip,  &(server_config.start),	"192.168.0.20"},
	{"end",		read_ip,  &(server_config.end),		"192.168.0.254"},
	{"interface",	read_str, &(server_config.interfaces),	"eth0"},
	{"option",	read_opt, &(server_config.options),	""},
	{"opt",		read_opt, &(server_config.options),	""},
	{"max_leases",	read_u32, &(server_config.max_leases),	"254"},
	{"offset",	read_u32, &(server_config.offset),	"1"},
	{"send_mult",	read_u32, &(server_config.send_mult),	"1"},
	{"keep_dns",    read_u32, &(server_config.keep_dns),    "0"},
	{"ippnp",	read_u32, &(server_config.ippnp),	"0"},
	{"remaining",	read_yn,  &(server_config.remaining),	"yes"},
	{"auto_time",	read_u32, &(server_config.auto_time),	"7200"},
	{"decline_time",read_u32, &(server_config.decline_time),"3600"},
	{"conflict_time",read_u32,&(server_config.conflict_time),"3600"},
	{"offer_time",	read_u32, &(server_config.offer_time),	"60"},
	{"min_lease",	read_u32, &(server_config.min_lease),	"60"},
	{"lease_file",	read_str, &(server_config.lease_file),	LEASES_FILE},
	{"pidfile",	read_str, &(server_config.pidfile),	"/var/run/udhcpd.pid"},
	{"notify_file", read_str, &(server_config.notify_file),	""},
	{"siaddr",	read_ip,  &(server_config.siaddr),	"0.0.0.0"},
	{"sname",	read_str, &(server_config.sname),	""},
	{"boot_file",	read_str, &(server_config.boot_file),	""},
	/*ADDME: static lease */
	{"",		NULL, 	  NULL,				""}
};


int read_config(const char *file)
{
	FILE *in;
	char buffer[READ_CONFIG_BUF_SIZE], *token, *line;
#ifdef UDHCP_DEBUG
	char orig[READ_CONFIG_BUF_SIZE];
#endif
	int i, lm = 0;

	for (i = 0; keywords[i].keyword[0]; i++)
		if (keywords[i].def[0])
			keywords[i].handler(keywords[i].def, keywords[i].var);

	if (!(in = fopen(file, "r"))) {
		LOG(LOG_ERR, "unable to open config file: %s", file);
		return 0;
	}
	
	while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
		lm++;
		if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0';
#ifdef UDHCP_DEBUG
		strcpy(orig, buffer);
#endif
		if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0';

		if (!(token = strtok(buffer, " \t"))) continue;
		if (!(line = strtok(NULL, ""))) continue;		
		
		/* eat leading whitespace */
		line = line + strspn(line, " \t=");
		/* eat trailing whitespace */
		for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--);
		line[i] = '\0';
		
		for (i = 0; keywords[i].keyword[0]; i++)
			if (!strcasecmp(token, keywords[i].keyword))
				if (!keywords[i].handler(line, keywords[i].var)) {
					LOG(LOG_ERR, "Failure parsing line %d of %s", lm, file);
					DEBUG(LOG_ERR, "unable to parse '%s'", orig);
					/* reset back to the default value */
					keywords[i].handler(keywords[i].def, keywords[i].var);
				}
	}
	fclose(in);
	return 1;
}


void write_leases(void)
{
	FILE *fp;
	unsigned int i;
	char buf[255];
	time_t curr = time(0);
	unsigned long tmp_time;
	
	if (!(fp = fopen(server_config.lease_file, "w"))) {
		LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
		return;
	}
	
	for (i = 0; i < server_config.max_leases; i++) {
		if (leases[i].yiaddr != 0) {

			/* screw with the time in the struct, for easier writing */
			tmp_time = leases[i].expires;

			if (server_config.remaining) {
				if (lease_expired(&(leases[i]))) {
					if (leases[i].expires + server_config.auto_time + 20 >= curr) {
						if (leases[i].ippnpaddr) {
							sprintf(buf, "ippnpremove %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s", 
								leases[i].chaddr[0], leases[i].chaddr[1], leases[i].chaddr[2],
								leases[i].chaddr[3], leases[i].chaddr[4], leases[i].chaddr[5],
								leases[i].yiaddr & 0xff, (leases[i].yiaddr >> 8) & 0xff,
								(leases[i].yiaddr >> 16) & 0xff, (leases[i].yiaddr >> 24) & 0xff,
								leases[i].ifname);
							DEBUG(LOG_INFO, "Exec %s", buf);
							system(buf);
						} else {
							sprintf(buf, "dhcpd.sh release %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s",
								leases[i].chaddr[0], leases[i].chaddr[1], leases[i].chaddr[2],
								leases[i].chaddr[3], leases[i].chaddr[4], leases[i].chaddr[5],
								leases[i].yiaddr & 0xff, (leases[i].yiaddr >> 8) & 0xff,
								(leases[i].yiaddr >> 16) & 0xff, (leases[i].yiaddr >> 24) & 0xff, 
								leases[i].ifname );
							DEBUG(LOG_INFO, "Exec %s", buf);
							system(buf);
						}
					}
					leases[i].expires = 0;
				}
				else leases[i].expires -= curr;
			} /* else stick with the time we got */
			leases[i].expires = htonl(leases[i].expires);
			fwrite(&leases[i], sizeof(struct dhcpOfferedAddr), 1, fp);

			/* Then restore it when done. */
			leases[i].expires = tmp_time;
		}
	}
	fclose(fp);
	
	if (server_config.notify_file) {
		sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file);
		system(buf);
	}
}


void read_leases(const char *file)
{
	FILE *fp;
	unsigned int i = 0;
	struct dhcpOfferedAddr lease;
	struct stat buf;
	
	if (!(fp = fopen(file, "r"))) {
		LOG(LOG_ERR, "Unable to open %s for reading", file);
		return;
	}

	if (fstat(fileno(fp), &buf) != 0) {
		LOG(LOG_ERR, "Unable to get filesize for %s", file);
		return;
	}

	if (buf.st_size % (sizeof lease) != 0) {
		LOG(LOG_ERR, "Probably unknown file structure in %s", file);
		return;
	}
	
	while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) {
		/* ADDME: is it a static lease */
		if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) {
			lease.expires = ntohl(lease.expires);
			if (!server_config.remaining) lease.expires -= time(0);
			if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires, lease.ippnpaddr, lease.ifname))) {
				LOG(LOG_WARNING, "Too many leases while loading %s\n", file);
				break;
			}				
			i++;
		}
	}
	DEBUG(LOG_INFO, "Read %d leases", i);
	fclose(fp);
}
/*
 * leases.c -- tools to manage DHCP leases
 * Russ Dill <Russ.Dill@xxxxxxx> July 2001
 */

#include <time.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "leases.h"
#include "arpping.h"
#include "common.h"


uint8_t blank_chaddr[] = {[0 ... 15] = 0};

/* clear every lease out that chaddr OR yiaddr matches and is nonzero */
void clear_lease(uint8_t *chaddr, uint32_t yiaddr)
{
	unsigned int i, j;

	for (j = 0; j < 16 && !chaddr[j]; j++);

	for (i = 0; i < server_config.max_leases; i++)
		if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) ||
		    (yiaddr && leases[i].yiaddr == yiaddr)) {
			memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr));
		}
}


/* add a lease into the table, clearing out any old ones */
struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease, uint32_t ippnpaddr, char *ifname)
{
	struct dhcpOfferedAddr *oldest;
	
	/* clean out any old ones */
	clear_lease(chaddr, yiaddr);
		
	oldest = oldest_expired_lease();
	
	if (oldest) {
		memcpy(oldest->chaddr, chaddr, 16);
		oldest->yiaddr = yiaddr;
		oldest->expires = time(0) + lease;
		oldest->ippnpaddr = ippnpaddr;
		strcpy(oldest->ifname, ifname);
	}
	
	return oldest;
}


/* true if a lease has expired */
int lease_expired(struct dhcpOfferedAddr *lease)
{
	return (lease->expires < (unsigned long) time(0));
}	


/* Find the oldest expired lease, NULL if there are no expired leases */
struct dhcpOfferedAddr *oldest_expired_lease(void)
{
	struct dhcpOfferedAddr *oldest = NULL;
	unsigned long oldest_lease = time(0);
	unsigned int i;

	
	for (i = 0; i < server_config.max_leases; i++)
		if (oldest_lease > leases[i].expires) {
			oldest_lease = leases[i].expires;
			oldest = &(leases[i]);
		}
	return oldest;
}


/* Find the first lease that matches chaddr, NULL if no match */
struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr)
{
	unsigned int i;

	for (i = 0; i < server_config.max_leases; i++)
		if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]);
	
	return NULL;
}


/* Find the first lease that matches yiaddr, NULL is no match */
struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr)
{
	unsigned int i;

	for (i = 0; i < server_config.max_leases; i++)
		if (leases[i].yiaddr == yiaddr) return &(leases[i]);
	
	return NULL;
}


/* check is an IP is taken, if it is, add it to the lease table */
static int check_ip(uint32_t addr)
{
	struct in_addr temp;

	if (arpping(addr, server_config.server[server_config.currentinterface],
			 server_config.arp[server_config.currentinterface], server_config.ifname[server_config.currentinterface]) == 0) {
		temp.s_addr = addr;
		LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds",
			inet_ntoa(temp), server_config.conflict_time);
		add_lease(blank_chaddr, addr, server_config.conflict_time, 0, "");
		return 1;
	} else return 0;
}


/* find an assignable address, it check_expired is true, we check all the expired leases as well.
 * Maybe this should try expired leases by age... */
uint32_t find_address(int check_expired)
{
	uint32_t addr;
	uint32_t ret = 0;
	struct dhcpOfferedAddr *lease = NULL;

	addr = ntohl(server_config.start); /* addr is in host order here */
	for (;addr <= ntohl(server_config.end); addr += server_config.offset) {

		/* ie, 192.168.55.0 */
		if (!(addr & 0xFF)) continue;

		/* ie, 192.168.55.255 */
		if ((addr & 0xFF) == 0xFF) continue;

		/* lease is not taken */
		ret = htonl(addr);
		if ((!(find_lease_by_yiaddr(ret))) &&
		     /* and it isn't on the network */
			!check_ip(ret)) {
			return ret;
		}
	}
	if (!check_expired)
		return 0;

	while ((lease = oldest_expired_lease()) != 0) {

		/* ie, 192.168.55.0 */
		/* if (!(addr & 0xFF)) continue */;

		/* ie, 192.168.55.255 */
		/* if ((addr & 0xFF) == 0xFF) continue */

		/* and it isn't on the network */
		if (!check_ip(lease->yiaddr)) {
			if (lease->expires + server_config.auto_time + 20 >= time(0)) {
				char buf[255];

				sprintf(buf, "dhcpd.sh release %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s",
					lease->chaddr[0], lease->chaddr[1], lease->chaddr[2],
					lease->chaddr[3], lease->chaddr[4], lease->chaddr[5],
					lease->yiaddr & 0xff, (lease->yiaddr >> 8) & 0xff,
					(lease->yiaddr >> 16) & 0xff, (lease->yiaddr >> 24) & 0xff,
					lease->ifname);
				system(buf);
				if (lease->ippnpaddr) {
					sprintf(buf, "ippnpremove %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s",
						lease->chaddr[0], lease->chaddr[1], lease->chaddr[2],
						lease->chaddr[3], lease->chaddr[4], lease->chaddr[5],
						(lease->yiaddr) & 0xff, (lease->yiaddr >> 8) & 0xff,
						(lease->yiaddr >> 16) & 0xff, (lease->yiaddr >> 24) & 0xff,
						lease->ifname);
					DEBUG(LOG_INFO, "Exec %s", buf);
					system(buf);
				}
			}
			return lease->yiaddr;
		}
	}
	return 0;
}
/* 
 * options.c -- DHCP server option packet tools 
 * Rewrite by Russ Dill <Russ.Dill@xxxxxxx> July 2001
 */
 
#include <stdlib.h>
#include <string.h>

#include "dhcpd.h"
#include "files.h"
#include "options.h"
#include "common.h"


/* supported options are easily added here */
struct dhcp_option dhcp_options[] = {
	/* name[10]	flags					code */
	{"subnet",	OPTION_IP | OPTION_REQ,			0x01},
	{"timezone",	OPTION_S32,				0x02},
	{"router",	OPTION_IP | OPTION_LIST | OPTION_REQ,	0x03},
	{"timesvr",	OPTION_IP | OPTION_LIST,		0x04},
	{"namesvr",	OPTION_IP | OPTION_LIST,		0x05},
	{"dns",		OPTION_IP | OPTION_LIST | OPTION_REQ,	0x06},
	{"logsvr",	OPTION_IP | OPTION_LIST,		0x07},
	{"cookiesvr",	OPTION_IP | OPTION_LIST,		0x08},
	{"lprsvr",	OPTION_IP | OPTION_LIST,		0x09},
	{"hostname",	OPTION_STRING | OPTION_REQ,		0x0c},
	{"bootsize",	OPTION_U16,				0x0d},
	{"domain",	OPTION_STRING | OPTION_REQ,		0x0f},
	{"swapsvr",	OPTION_IP,				0x10},
	{"rootpath",	OPTION_STRING,				0x11},
	{"ipttl",	OPTION_U8,				0x17},
	{"mtu",		OPTION_U16,				0x1a},
	{"broadcast",	OPTION_IP | OPTION_REQ,			0x1c},
	{"ntpsrv",	OPTION_IP | OPTION_LIST,		0x2a},
	{"wins",	OPTION_IP | OPTION_LIST,		0x2c},
	{"requestip",	OPTION_IP,				0x32},
	{"lease",	OPTION_U32,				0x33},
	{"dhcptype",	OPTION_U8,				0x35},
	{"serverid",	OPTION_IP,				0x36},
	{"message",	OPTION_STRING,				0x38},
	{"tftp",	OPTION_STRING,				0x42},
	{"bootfile",	OPTION_STRING,				0x43},
	{"",		0x00,				0x00}
};

/* Lengths of the different option types */
int option_lengths[] = {
	[OPTION_IP] =		4,
	[OPTION_IP_PAIR] =	8,
	[OPTION_BOOLEAN] =	1,
	[OPTION_STRING] =	1,
	[OPTION_U8] =		1,
	[OPTION_U16] =		2,
	[OPTION_S16] =		2,
	[OPTION_U32] =		4,
	[OPTION_S32] =		4
};


/* get an option with bounds checking (warning, not aligned). */
uint8_t *get_option(struct dhcpMessage *packet, int code)
{
	int i, length;
	uint8_t *optionptr;
	int over = 0, done = 0, curr = OPTION_FIELD;
	
	optionptr = packet->options;
	i = 0;
	length = 308;
	while (!done) {
		if (i >= length) {
			LOG(LOG_WARNING, "bogus packet, option fields too long.");
			return NULL;
		}
		if (optionptr[i + OPT_CODE] == code) {
			if (i + 1 + optionptr[i + OPT_LEN] >= length) {
				LOG(LOG_WARNING, "bogus packet, option fields too long.");
				return NULL;
			}
			return optionptr + i + 2;
		}			
		switch (optionptr[i + OPT_CODE]) {
		case DHCP_PADDING:
			i++;
			break;
		case DHCP_OPTION_OVER:
			if (i + 1 + optionptr[i + OPT_LEN] >= length) {
				LOG(LOG_WARNING, "bogus packet, option fields too long.");
				return NULL;
			}
			over = optionptr[i + 3];
			i += optionptr[OPT_LEN] + 2;
			break;
		case DHCP_END:
			if (curr == OPTION_FIELD && over & FILE_FIELD) {
				optionptr = packet->file;
				i = 0;
				length = 128;
				curr = FILE_FIELD;
			} else if (curr == FILE_FIELD && over & SNAME_FIELD) {
				optionptr = packet->sname;
				i = 0;
				length = 64;
				curr = SNAME_FIELD;
			} else done = 1;
			break;
		default:
			i += optionptr[OPT_LEN + i] + 2;
		}
	}
	return NULL;
}


/* return the position of the 'end' option (no bounds checking) */
int end_option(uint8_t *optionptr) 
{
	int i = 0;
	
	while (optionptr[i] != DHCP_END) {
		if (optionptr[i] == DHCP_PADDING) i++;
		else i += optionptr[i + OPT_LEN] + 2;
	}
	return i;
}


/* add an option string to the options (an option string contains an option code,
 * length, then data) */
int add_option_string(uint8_t *optionptr, uint8_t *string, uint32_t leasenumber)
{
	int end = end_option(optionptr);
	uint8_t buffer[255];
	
	/* end position + string length + option code/length + end option */
	if (end + string[OPT_LEN] + 2 + 1 >= 308) {
		LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]);
		return 0;
	}
	DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]);

	memcpy(buffer, string, string[OPT_LEN] + 2);

	if (buffer[OPT_CODE] == 0x03) {
		if (server_config.offset != 1) {
			uint32_t addr;

			memcpy(&addr, &buffer[2], 4);
			addr = ntohl(addr);
			addr += (server_config.offset * leasenumber);
			addr = htonl(addr);
			memcpy(&buffer[2], &addr, 4);
		}	
	}

	if (buffer[OPT_CODE] == 0x05 || buffer[OPT_CODE] == 0x06) {
		if (server_config.offset != 1 && !server_config.keep_dns) {
			uint32_t addr;

			memcpy(&addr, &buffer[2], 4);
			addr = ntohl(addr);
			addr += (server_config.offset * leasenumber);
			addr = htonl(addr);
			memcpy(&buffer[2], &addr, 4);
		}	
	}

	memcpy(optionptr + end, buffer, buffer[OPT_LEN] + 2);
	optionptr[end + string[OPT_LEN] + 2] = DHCP_END;
	return string[OPT_LEN] + 2;
}


/* add a one to four byte option to a packet */
int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data)
{
	char length = 0;
	int i;
	uint8_t option[2 + 4];
	uint8_t *u8;
	uint16_t *u16;
	uint32_t *u32;
	uint32_t aligned;
	u8 = (uint8_t *) &aligned;
	u16 = (uint16_t *) &aligned;
	u32 = &aligned;

	for (i = 0; dhcp_options[i].code; i++)
		if (dhcp_options[i].code == code) {
			length = option_lengths[dhcp_options[i].flags & TYPE_MASK];
		}
		
	if (!length) {
		DEBUG(LOG_ERR, "Could not add option 0x%02x", code);
		return 0;
	}
	
	option[OPT_CODE] = code;
	option[OPT_LEN] = length;

	switch (length) {
		case 1: *u8 =  data; break;
		case 2: *u16 = data; break;
		case 4: *u32 = data; break;
	}
	memcpy(option + 2, &aligned, length);
	return add_option_string(optionptr, option, 1);
}


/* find option 'code' in opt_list */
struct option_set *find_option(struct option_set *opt_list, char code)
{
	while (opt_list && opt_list->data[OPT_CODE] < code)
		opt_list = opt_list->next;

	if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list;
	else return NULL;
}


/* add an option to the opt_list */
void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length)
{
	struct option_set *existing, *new, **curr;

	/* add it to an existing option */
	if ((existing = find_option(*opt_list, option->code))) {
		DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name);
		if (option->flags & OPTION_LIST) {
			if (existing->data[OPT_LEN] + length <= 255) {
				existing->data = realloc(existing->data, 
						existing->data[OPT_LEN] + length + 2);
				memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
				existing->data[OPT_LEN] += length;
			} /* else, ignore the data, we could put this in a second option in the future */
		} /* else, ignore the new data */
	} else {
		DEBUG(LOG_INFO, "Attaching option %s to list", option->name);
		
		/* make a new option */
		new = xmalloc(sizeof(struct option_set));
		new->data = xmalloc(length + 2);
		new->data[OPT_CODE] = option->code;
		new->data[OPT_LEN] = length;
		memcpy(new->data + 2, buffer, length);
		
		curr = opt_list;
		while (*curr && (*curr)->data[OPT_CODE] < option->code)
			curr = &(*curr)->next;
			
		new->next = *curr;
		*curr = new;		
	}
}
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <features.h>
#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#endif
#include <errno.h>

#include "packet.h"
#include "dhcpd.h"
#include "options.h"
#include "common.h"


void init_header(struct dhcpMessage *packet, char type)
{
	memset(packet, 0, sizeof(struct dhcpMessage));
	switch (type) {
	case DHCPDISCOVER:
	case DHCPREQUEST:
	case DHCPRELEASE:
	case DHCPINFORM:
		packet->op = BOOTREQUEST;
		break;
	case DHCPOFFER:
	case DHCPACK:
	case DHCPNAK:
		packet->op = BOOTREPLY;
	}
	packet->htype = ETH_10MB;
	packet->hlen = ETH_10MB_LEN;
	packet->cookie = htonl(DHCP_MAGIC);
	packet->options[0] = DHCP_END;
	add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
}


/* read a packet from socket fd, return -1 on read error, -2 on packet error */
int get_packet(struct dhcpMessage *packet, int fd)
{
	int bytes;
	int i;
	const char broken_vendors[][8] = {
		"MSFT 98",
		""
	};
	char unsigned *vendor;

	memset(packet, 0, sizeof(struct dhcpMessage));
	bytes = read(fd, packet, sizeof(struct dhcpMessage));
	if (bytes < 0) {
		DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring");
		return -1;
	}

	if (ntohl(packet->cookie) != DHCP_MAGIC) {
		LOG(LOG_ERR, "received bogus message, ignoring");
		return -2;
	}
	DEBUG(LOG_INFO, "Received a packet");
	
	if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) {
		for (i = 0; broken_vendors[i][0]; i++) {
			if (vendor[OPT_LEN - 2] == (uint8_t) strlen(broken_vendors[i]) &&
			    !strncmp(vendor, broken_vendors[i], vendor[OPT_LEN - 2])) {
			    	DEBUG(LOG_INFO, "broken client (%s), forcing broadcast",
			    		broken_vendors[i]);
			    	packet->flags |= htons(BROADCAST_FLAG);
			}
		}
	}
			    	

	return bytes;
}


uint16_t checksum(void *addr, int count)
{
	/* Compute Internet Checksum for "count" bytes
	 *         beginning at location "addr".
	 */
	register int32_t sum = 0;
	uint16_t *source = (uint16_t *) addr;

	while (count > 1)  {
		/*  This is the inner loop */
		sum += *source++;
		count -= 2;
	}

	/*  Add left-over byte, if any */
	if (count > 0) {
		/* Make sure that the left-over byte is added correctly both
		 * with little and big endian hosts */
		uint16_t tmp = 0;
		*(uint8_t *) (&tmp) = * (uint8_t *) source;
		sum += tmp;
	}
	/*  Fold 32-bit sum to 16 bits */
	while (sum >> 16)
		sum = (sum & 0xffff) + (sum >> 16);

	return ~sum;
}


/* Constuct a ip/udp header for a packet, and specify the source and dest hardware address */
int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
		   uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex)
{
	int fd;
	int result = -1;
	struct sockaddr_ll dest;
	struct udp_dhcp_packet packet;
	int i;

	if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
		DEBUG(LOG_ERR, "socket call failed: %m");
		return -1;
	}
	
	memset(&dest, 0, sizeof(dest));
	memset(&packet, 0, sizeof(packet));
	
	dest.sll_family = AF_PACKET;
	dest.sll_protocol = htons(ETH_P_IP);
	dest.sll_ifindex = ifindex;
	dest.sll_halen = 6;
	memcpy(dest.sll_addr, dest_arp, 6);
	if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
		DEBUG(LOG_ERR, "bind call failed: %m");
		close(fd);
		return -1;
	}

	packet.ip.protocol = IPPROTO_UDP;
	packet.ip.saddr = source_ip;
	packet.ip.daddr = dest_ip;
	packet.udp.source = htons(source_port);
	packet.udp.dest = htons(dest_port);
	packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */
	packet.ip.tot_len = packet.udp.len;
	memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
	packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet));
	
	packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
	packet.ip.ihl = sizeof(packet.ip) >> 2;
	packet.ip.version = IPVERSION;
	packet.ip.ttl = IPDEFTTL;
	packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip));

	LOG(LOG_INFO, "raw_packet: send %d times", server_config.send_mult);
	for (i = 0; i < server_config.send_mult; i++) {
		result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));
		if (result <= 0) {
			DEBUG(LOG_ERR, "write on socket failed: %m");
		}
	}
	close(fd);
	return result;
}


/* Let the kernel do all the work for packet generation */
int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port,
		   uint32_t dest_ip, int dest_port)
{
	int n = 1;
	int fd, result;
	struct sockaddr_in client;
	
	if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
		return -1;
	
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1)
		return -1;

	memset(&client, 0, sizeof(client));
	client.sin_family = AF_INET;
	client.sin_port = htons(source_port);
	client.sin_addr.s_addr = source_ip;

	if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
		return -1;

	memset(&client, 0, sizeof(client));
	client.sin_family = AF_INET;
	client.sin_port = htons(dest_port);
	client.sin_addr.s_addr = dest_ip; 

	if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1)
		return -1;

	result = write(fd, payload, sizeof(struct dhcpMessage));
	close(fd);
	return result;
}	
/*
 * socket.c -- DHCP server client/server socket creation
 *
 * udhcp client/server
 * Copyright (C) 1999 Matthew Ramsay <matthewr@xxxxxxxxxxxxxx>
 *			Chris Trew <ctrew@xxxxxxxxxxxxxx>
 *
 * Rewrite by Russ Dill <Russ.Dill@xxxxxxx> July 2001
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <features.h>
#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#endif

#include "socket.h"
#include "common.h"

int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *arp)
{
	int fd;
	struct ifreq ifr;
	struct sockaddr_in *our_ip;

	memset(&ifr, 0, sizeof(struct ifreq));
	if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
		ifr.ifr_addr.sa_family = AF_INET;
		strcpy(ifr.ifr_name, interface);

		if (addr) { 
			if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
				our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
				*addr = our_ip->sin_addr.s_addr;
				DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
			} else {
				LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %m");
				return -1;
			}
		}
		
		if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
			DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
			*ifindex = ifr.ifr_ifindex;
		} else {
			LOG(LOG_ERR, "SIOCGIFINDEX failed!: %m");
			return -1;
		}
		if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
			memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
			DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
				arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
		} else {
			LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %m");
			return -1;
		}
	} else {
		LOG(LOG_ERR, "socket failed!: %m");
		return -1;
	}
	close(fd);
	return 0;
}


int listen_socket(uint32_t ip, int port, char *inf)
{
	struct ifreq interface;
	int fd;
	struct sockaddr_in addr;
	int n = 1;

	DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s", ip, port, inf);
	if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		DEBUG(LOG_ERR, "dhcp socket call failed: %m");
		return -1;
	}
	
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = ip;

	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) {
		close(fd);
		return -1;
	}
	if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) {
		close(fd);
		return -1;
	}

	strncpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ);
	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) {
		close(fd);
		return -1;
	}

	if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
		close(fd);
		return -1;
	}
	
	return fd;
}

int arp_socket(char *inf, int ifindex)
{
	struct sockaddr_ll sll;
	int fd;

	DEBUG(LOG_INFO, "Opening arp socket on %s", inf);

	if ((fd = socket(PF_PACKET, SOCK_DGRAM, 0)) < 0) {
		DEBUG(LOG_ERR, "arp socket call failed: %m");
		return -1;
	}

	memset(&sll, 0, sizeof(sll));
	sll.sll_family = AF_PACKET;
	sll.sll_protocol = htons(ETH_P_ARP);
	sll.sll_ifindex = ifindex;
	if (bind(fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
		close(fd);
		DEBUG(LOG_ERR, "arp bind call failed: %m");
		return -1;
	}

	return fd;
}
#!/bin/ash

# $1 mac
# $2 gwip
# $3 leaseip
# $4 clientip
# $5 clientip +/- 1
# $6 interface

# $1 mac
# $2 leaseip
# $3 clientip
# $4 interface

. /system/data/network.cfg

if [ "$#" = "6" ]; then
	mac=$1
	gwip=$2
	leaseip=$3
	fixip=$4
	fixip1=$5
	interface=$6
else if [ "$#" = "4" ]; then
	mac=$1
	gwip=`echo $2 | awk -F \. '/./ { print $1 "." $2 "." $3 ".1" }'`
	leaseip=$2
	fixip=$3
	fixip1=`echo $3 | awk -F \. '/./ { if ($4 == 1) print $1 "." $2 "." $3 "." $4 + 1; else print $1 "." $2 "." $3 "." $4 - 1 }'`
	interface=$4
else
	logger ippnpadd wrong number of params
	exit
fi
fi

# check reserved subnet - if yes, do nothing (allow switches and APs to be managed from gateway
rsvsubnet=`echo $NET_LANIPADDRESS | awk -F \. '/./ { print $1 "." $2 "." $3 }'`
clientsubnet=`echo $fixip | awk -F \. '/./ { print $1 "." $2 "." $3 }'`
grep -i $fixip /system/data/ipdevices.cfg
if [ "$?" = 0 -o "$rsvsubnet" = "$clientsubnet" ]; then
	logger ippnpadd Reserved subnet request dropped for $fixip
	exit
fi

lanprefix=`echo $NET_LANLEASESTART | awk -F \. '/./ { print $1 "." $2 }'`
fixip1=$lanprefix.0.1

logger ippnpadd $mac $gwip $leaseip $fixip $fixip1 $interface

arptables -A OUTPUT -o $interface -d $leaseip -j mangle --mangle-ip-d $fixip --mangle-ip-s $fixip1
arptables -A INPUT -i $interface -s $fixip -j mangle --mangle-ip-s $leaseip --mangle-ip-d $gwip

iptables -t mangle -I PREROUTING -i $interface -s $fixip -j SADDR --to-source $leaseip
iptables -t mangle -I POSTROUTING -o $interface -d $leaseip -j DADDR --to-dest $fixip

dhcpd.sh dhcprequest $mac $leaseip $interface IPPNP

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux