Re: AW: Add new target in mangle table

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

 



-------- Original-Nachricht --------
> Datum: Mon, 14 Apr 2008 18:58:41 +0200 (CEST)
> Von: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>
> An: manuprivat@xxxxxx
> CC: netfilter-devel@xxxxxxxxxxxxxxx
> Betreff: Re: AW: Add new target in mangle table

> 
> On Monday 2008-04-14 18:34, manu wrote:
> >> >>
> >> >># iptables -t mangle -I PREROUTING -i eth2 -s 192.168.0.168 -j SADDR
> >> >>--to-source 10.0.19.2
> >> >
> >> One question this throws up... how do you know the address is
> >> 192.168.0.168?
> >
> >Actually, I dont know that! It is only an example to show the different
> >IP-ranges. Excuse my improper representation.
> 
> The question is more of a technical one-- if you do not know the
> source address the client will be using, how can you reliably
> mangle the address?


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.


-- 
GMX startet ShortView.de. Hier findest Du Leute mit Deinen Interessen!
Jetzt dabei sein: http://www.shortview.de/?mc=sv_ext_mf@gmx
/* dhcpd.c
 *
 * udhcp 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 <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>

#include <netpacket/packet.h>

#include "dhcpd.h"
#include "arpping.h"
#include "socket.h"
#include "options.h"
#include "files.h"
#include "serverpacket.h"
#include "common.h"
#include "signalpipe.h"


/* globals */
struct dhcpOfferedAddr *leases;
struct server_config_t server_config;


#ifdef COMBINED_BINARY	
int udhcpd_main(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif
{
	fd_set rfds;
	fd_set thefds;
	struct timeval tv;
	int bytes, retval;
	struct dhcpMessage packet;
	uint8_t *state;
	uint8_t *server_id, *requested;
	uint32_t server_id_align, requested_align;
	unsigned long timeout_end;
	struct option_set *option;
	struct dhcpOfferedAddr *lease;
	int max_sock = 0;
	unsigned long num_ips;
	char buffer[100];
	char *pname;
	int i;
	int lastindex = 0;
	
	memset(&server_config, 0, sizeof(struct server_config_t));
	read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);

	/* Start the log, sanitize fd's, and write a pid file */
	start_log_and_pid("udhcpd", server_config.pidfile);

	if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
		memcpy(&server_config.lease, option->data + 2, 4);
		server_config.lease = ntohl(server_config.lease);
	}
	else server_config.lease = LEASE_TIME;

	/* Sanity check */
	server_config.end = ntohl(server_config.start);
	server_config.end = htonl(server_config.end + (server_config.max_leases - 1) * server_config.offset);
	num_ips = (ntohl(server_config.end) - ntohl(server_config.start)) / server_config.offset + 1;
	if (server_config.max_leases > num_ips) {
		LOG(LOG_ERR, "max_leases value (%lu) not sane, "
			"setting to %lu instead",
			server_config.max_leases, num_ips);
		server_config.max_leases = num_ips;
	}

	leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr));
	read_leases(server_config.lease_file);

	server_config.numofinterfaces = 0;
	pname = strtok(server_config.interfaces, " ");
	while (pname) {
		server_config.ifname[server_config.numofinterfaces] = pname;
		server_config.fds[server_config.numofinterfaces] = -1;
		server_config.arpfds[server_config.numofinterfaces] = -1;
		if (read_interface(server_config.ifname[server_config.numofinterfaces],
				&server_config.ifindex[server_config.numofinterfaces],
				&server_config.server[server_config.numofinterfaces],
				server_config.arp[server_config.numofinterfaces]) < 0)
			return 1;
		server_config.numofinterfaces++;
		pname = strtok(0, " ");
	}
	server_config.currentinterface = 0;

/* #ifndef UDHCP_DEBUG */
	background(server_config.pidfile); /* hold lock during fork. */
/* #endif */

	FD_ZERO(&thefds);
	FD_ZERO(&rfds);

	/* Setup the signal pipe */
	udhcp_sp_setup();

	timeout_end = time(0) + server_config.auto_time;
	while(1) { /* loop until universe collapses */

		for (i = 0; i < server_config.numofinterfaces; i++) {
			if (server_config.fds[i] < 0)
				if ((server_config.fds[i] = listen_socket(INADDR_ANY, SERVER_PORT,
						server_config.ifname[i])) < 0) {
					LOG(LOG_ERR, "FATAL: couldn't create server socket, %m");
					return 2;
				}

			if (server_config.ippnp) {
				if (server_config.arpfds[i] < 0) {
					if ((server_config.arpfds[i] = 
						arp_socket(server_config.ifname[i], server_config.ifindex[i])) < 0) {
						LOG(LOG_ERR, "FATAL: couldn't create arp socket, %m");
						return 2;
					}
				}
			}

			max_sock = udhcp_sp_fd_set(&thefds, server_config.fds[i]);
			if (server_config.ippnp) {
				max_sock = udhcp_sp_fd_set(&thefds, server_config.arpfds[i]);
			}
		}
		if (server_config.auto_time) {
			tv.tv_sec = timeout_end - time(0);
			tv.tv_usec = 0;
		}
		memcpy(&rfds, &thefds, sizeof(fd_set));
		if (!server_config.auto_time || tv.tv_sec > 0) {
			retval = select(max_sock + 1, &rfds, NULL, NULL, 
					server_config.auto_time ? &tv : NULL);
		} else retval = 0; /* If we already timed out, fall through */

		if (retval == 0) {
			write_leases();
			timeout_end = time(0) + server_config.auto_time;
			continue;
		} else if (retval < 0 && errno != EINTR) {
			DEBUG(LOG_INFO, "error on select");
			continue;
		}
		
		switch (udhcp_sp_read(&rfds)) {
		case SIGUSR1:
			LOG(LOG_INFO, "Received a SIGUSR1");
			write_leases();
			/* why not just reset the timeout, eh */
			timeout_end = time(0) + server_config.auto_time;
			continue;
		case SIGTERM:
			LOG(LOG_INFO, "Received a SIGTERM");
			write_leases();
			return 0;
		case 0: break;		/* no signal */
		default: continue;	/* signal or error (probably EINTR) */
		}

		for (i = lastindex; i < (server_config.numofinterfaces * 2); i++) {
			if (FD_ISSET(server_config.fds[i % server_config.numofinterfaces], &rfds)) {
				server_config.currentinterface = i % server_config.numofinterfaces;
				lastindex = server_config.currentinterface + 1;
				break;
			}

			if (server_config.ippnp) {
				if (FD_ISSET(server_config.arpfds[i % server_config.numofinterfaces], &rfds)) {
					server_config.currentinterface = i % server_config.numofinterfaces;
					lastindex = server_config.currentinterface + 1;
					break;
				}
			}

		}

		if (server_config.ippnp) {
			if (FD_ISSET(server_config.arpfds[server_config.currentinterface], &rfds)) {
				unsigned char buf[1024];
				struct sockaddr_ll sll;
				int sll_len = sizeof(sll);
				int n;

				n = recvfrom(server_config.arpfds[server_config.currentinterface], 
						buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len);
				if (n < 0) {
					DEBUG(LOG_INFO, "error receiving arp");
				}
				else {
					DEBUG(LOG_INFO, "received arp on %s %d", server_config.ifname[server_config.currentinterface], n);
					handleArpPacket(buf);
				}
			}
		}

		if (FD_ISSET(server_config.fds[server_config.currentinterface], &rfds)) {
			if ((bytes = get_packet(&packet, server_config.fds[server_config.currentinterface])) < 0) {
				if (bytes == -1 && errno != EINTR) {
					DEBUG(LOG_INFO, "error on read, %m, reopening socket");
					close(server_config.fds[server_config.currentinterface]);
					max_sock = udhcp_sp_fd_unset(&thefds, server_config.fds[i]);
					server_config.fds[server_config.currentinterface] = -1;
				}
				continue;
			}
		}
		else
			continue;

		if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
			DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
			continue;
		}
		
		/* ADDME: look for a static lease */
		lease = find_lease_by_chaddr(packet.chaddr);

		if (lease && lease->ippnpaddr) { /* The computer with this mac was seen with fixed ip address before */
			char buf[256];

			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);
			system(buf);
		}

		switch (state[0]) {
		case DHCPDISCOVER:
			DEBUG(LOG_INFO,"received DISCOVER");

			sprintf(buffer, "dhcpd.sh discover %02X:%02X:%02X:%02X:%02X:%02X %s",
				packet.chaddr[0], packet.chaddr[1], packet.chaddr[2],
				packet.chaddr[3], packet.chaddr[4], packet.chaddr[5], server_config.ifname[server_config.currentinterface]);
			if (WEXITSTATUS(system(buffer)) == 0) {
				if (sendOffer(&packet) < 0) {
					LOG(LOG_ERR, "send OFFER failed");
				}
			}
			break;			
 		case DHCPREQUEST:
			DEBUG(LOG_INFO, "received REQUEST");

			requested = get_option(&packet, DHCP_REQUESTED_IP);
			server_id = get_option(&packet, DHCP_SERVER_ID);

			if (requested) memcpy(&requested_align, requested, 4);
			if (server_id) memcpy(&server_id_align, server_id, 4);
		
			if (lease) { /*ADDME: or static lease */

				sprintf(buffer, "dhcpd.sh dhcprequest %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s",
					packet.chaddr[0], packet.chaddr[1], packet.chaddr[2],
					packet.chaddr[3], packet.chaddr[4], packet.chaddr[5],
					lease->yiaddr & 0xff, (lease->yiaddr >> 8) & 0xff,
					(lease->yiaddr >> 16) & 0xff, (lease->yiaddr >> 24) & 0xff,
					server_config.ifname[server_config.currentinterface]);

				if (server_id) {
					/* SELECTING State */
					DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
					if (server_id_align == server_config.server[server_config.currentinterface] && requested && 
					    requested_align == lease->yiaddr) {
						if (WEXITSTATUS(system(buffer)) == 0)
							sendACK(&packet, lease->yiaddr);
					}
				} else {
					if (requested) {
						/* INIT-REBOOT State */
						if (lease->yiaddr == requested_align) {
							if (WEXITSTATUS(system(buffer)) == 0)
								sendACK(&packet, lease->yiaddr);
						}
						else sendNAK(&packet);
					} else {
						/* RENEWING or REBINDING State */
						if (lease->yiaddr == packet.ciaddr) {
							if (WEXITSTATUS(system(buffer)) == 0)
								sendACK(&packet, lease->yiaddr);
						}
						else {
							/* don't know what to do!!!! */
							sendNAK(&packet);
						}
					}						
				}
			
			/* what to do if we have no record of the client */
			} else if (server_id) {
				/* SELECTING State */

			} else if (requested) {
				/* INIT-REBOOT State */
				if ((lease = find_lease_by_yiaddr(requested_align))) {
					if (lease_expired(lease)) {
						/* probably best if we drop this lease */
						memset(lease->chaddr, 0, 16);
					/* make some contention for this address */
					} else sendNAK(&packet);
				} else if (requested_align < server_config.start || 
					   requested_align > server_config.end ||
					   ((requested_align - server_config.start) % server_config.start) == 1) {
					sendNAK(&packet);
				} /* else remain silent */

			} else {
				 /* RENEWING or REBINDING State */
			}
			break;
		case DHCPDECLINE:
			DEBUG(LOG_INFO,"received DECLINE");
			if (lease) {
				memset(lease->chaddr, 0, 16);
				lease->expires = time(0) + server_config.decline_time;
			}			
			break;
		case DHCPRELEASE:
			DEBUG(LOG_INFO,"received RELEASE");

			if (lease) {
				sprintf(buffer, "dhcpd.sh release %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s",
					packet.chaddr[0], packet.chaddr[1], packet.chaddr[2],
					packet.chaddr[3], packet.chaddr[4], packet.chaddr[5],
					lease->yiaddr & 0xff, (lease->yiaddr >> 8) & 0xff,
					(lease->yiaddr >> 16) & 0xff, (lease->yiaddr >> 24) & 0xff,
					server_config.ifname[server_config.currentinterface]);
				system(buffer);			
				lease->expires = time(0);
			}
			break;
		case DHCPINFORM:
			DEBUG(LOG_INFO,"received INFORM");
			if (lease) {
				sprintf(buffer, "dhcpd.sh inform %02X:%02X:%02X:%02X:%02X:%02X %d.%d.%d.%d %s",
					packet.chaddr[0], packet.chaddr[1], packet.chaddr[2],
					packet.chaddr[3], packet.chaddr[4], packet.chaddr[5],
					lease->yiaddr & 0xff, (lease->yiaddr >> 8) & 0xff,
					(lease->yiaddr >> 16) & 0xff, (lease->yiaddr >> 24) & 0xff,
					server_config.ifname[server_config.currentinterface]);
				system(buffer);						
				send_inform(&packet, lease->yiaddr);
			}
			break;	
		default:
			LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
		}
	}

	return 0;
}

Attachment: dhcpd.sh
Description: application/shellscript


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

  Powered by Linux