Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 Nov 2003 14:26:31 +0200
From:      "Ivo Vachkov" <ivo@bsdmail.org>
To:        freebsd-ipfw@freebsd.org
Cc:        freebsd-net@freebsd.org
Message-ID:  <20031130122631.7868.qmail@bsdmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi all,

I've been trying to write some code using divert(4) sockets, but i meet the following difficulties:
    - when i get diverted packet it has both source and destination IP addresses the same. The attached code shows:

    192.168.0.2 -> 192.168.0.2
    getting 84 bytes, real: 84

and the way I run it is (on 192.168.0.2):

    ipfw add 100 divert 8670 ip from any to 192.168.0.1
    burstd

then on 192.168.0.2 I issue "ping 192.168.0.1"

    - the manual says this happens with recvfrom()/sendto(), but recv() is mentioned to be same as recvfrom() and read()/write() sometimes fail.

After digging some kernel code I've found that around line 167 in ip_divert.c we have:

	/*
	 * Record receive interface address, if any.
	 * But only for incoming packets.
	 */
	divsrc.sin_addr.s_addr = 0;
	if (incoming) {
		struct ifaddr *ifa;

		/* Sanity check */
		KASSERT((m->m_flags & M_PKTHDR), ("%s: !PKTHDR", __FUNCTION__));

		/* Find IP address for receive interface */
		TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
			if (ifa->ifa_addr == NULL)
				continue;
			if (ifa->ifa_addr->sa_family != AF_INET)
				continue;
			divsrc.sin_addr =
			    ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
			break;
		}
	}

which (as I think) changes the address of diverted packet. What is the reason for that and are there any workarounds to get real source and destination IP addresses from a diverted packet. I need both because I try to make connection tracking based on src<->dst .

Any help with that is appretiated. Any divert code welcome. I've looked through natd.c and it was helpfull.

    Ivo Vachkov

P.S. Excuse my:
    - English
    - long pastes
    - (sometimes) lack of kernel code understanding
-- 
_______________________________________________
Get your free email from http://mymail.bsdmail.com

Powered by Outblaze

[-- Attachment #2 --]
CC	=	cc
CFLAGS	=	-g -Wall -Wpointer-arith
LIBS	=

SRC	=	burstd.c
OBJ	=	
PROG	=	burstd

all:$(SRC)
	$(CC) $(CFLAGS) -c *.c
	$(CC) $(CFLAGS) -o $(PROG) $(SRC) $(OBJ) $(LIBS)

clean:
	rm -f $(PROG) *.core *.o etc/*

[-- Attachment #3 --]
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <machine/in_cksum.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <arpa/inet.h>
#include <alias.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

// #include "queue.h"

#define CONF		"burstd.conf"

/* Connection type; bursting */
typedef struct _flow
{
	struct in_addr 	src_addr;
	struct in_addr	dst_addr;
	long long	bytes;
	long long	last;
	int		alive;
	int 		used;
}CONNECTION;

typedef struct _node
{
	struct _node 	*next;
	struct _flow	*data;
}CONN_LIST;

long long 	limit, rate;

/* Some functions */

/* signal.c */
void sig_alrm_hnd(int sig);
/* init.c */
void set_rate_limit();
/* parent.c */
int search_conn(CONNECTION cons[], struct in_addr saddr, struct in_addr daddr);
int add_conn(CONNECTION cons[], CONNECTION s_conn);

[-- Attachment #4 --]
#include "burstd.h"

int main(int argc, char **argv)
{
	int 			divIO;
	fd_set			readmask;
	struct sockaddr_in 	sa;
	int 			bytes, oldbytes, addrSize;
	struct ip*		ip;
	void*			buff;
	

	buff = (void *)malloc(IP_MAXPACKET);
	memset((void *)buff, 0, IP_MAXPACKET);
	
	if((divIO = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT)) == -1)
	{
		perror("socket");
		exit(-1);
	}

	sa.sin_family = AF_INET;
	sa.sin_addr.s_addr = INADDR_ANY;
	sa.sin_port = htons(8670);
	if(bind(divIO, (struct sockaddr*)&sa, sizeof(struct sockaddr)) == -1)
	{
		perror("bind");
		exit(-1);
	}

	FD_ZERO(&readmask);
	FD_SET(divIO, &readmask);
	
	while(1)
	{
		if(select(getdtablesize() + 1, &readmask, NULL, NULL, NULL) == -1)
		{
			perror("select");
			exit(-1);
		}
		if(FD_ISSET(divIO, &readmask))
		{
			addrSize = sizeof(sa);
			if((oldbytes = recvfrom(divIO, buff, IP_MAXPACKET, 0, (struct sockaddr*) &sa, &addrSize)) == -1)
			{
				perror("recvfrom");
				exit(-1);
			}
		
			ip = (struct ip*) buff;
			printf("%s -> %s\n", inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst));
			printf("getting %d bytes, real: %d\n", oldbytes, ntohs(ip->ip_len));
			printf("sa.sin_addr.s_addr = %s\n", inet_ntoa(sa.sin_addr));
			
			if((bytes = sendto(divIO, buff, oldbytes, 0, (struct sockaddr*) &sa, addrSize)) != oldbytes)
			{
				printf("Different recieved/sent values: %d <-> %d\n", oldbytes, bytes);
				perror("sendto");
				exit(-1);
			}
		}
	}
	return 0;
}

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031130122631.7868.qmail>