Exemple #1
0
int main (int argc, char** argv)
{
	int			divertIn;
	int			divertOut;
	int			divertInOut;
	int			routeSock;
	struct sockaddr_in	addr;
	fd_set			readMask;
	fd_set			writeMask;
	int			fdMax;
/* 
 * Initialize packet aliasing software.
 * Done already here to be able to alter option bits
 * during command line and configuration file processing.
 */
	PacketAliasInit ();
/*
 * Parse options.
 */
	inPort			= 0;
	outPort			= 0;
	verbose 		= 0;
	inOutPort		= 0;
	ifName			= NULL;
	ifMTU			= -1;
	background		= 0;
	running			= 1;
	assignAliasAddr		= 0;
	aliasAddr.s_addr	= INADDR_NONE;
	aliasOverhead		= 12;
	dynamicMode		= 0;
 	logDropped		= 0;
 	logFacility		= LOG_DAEMON;
/*
 * Mark packet buffer empty.
 */
	packetSock		= -1;
	packetDirection		= DONT_KNOW;

	ParseArgs (argc, argv);
/*
 * Open syslog channel.
 */
	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
		 logFacility);
/*
 * Check that valid aliasing address has been given.
 */
	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
		errx (1, "aliasing address not given");

	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
		errx (1, "both alias address and interface "
			 "name are not allowed");
/*
 * Check that valid port number is known.
 */
	if (inPort != 0 || outPort != 0)
		if (inPort == 0 || outPort == 0)
			errx (1, "both input and output ports are required");

	if (inPort == 0 && outPort == 0 && inOutPort == 0)
		ParseOption ("port", DEFAULT_SERVICE);

/*
 * Check if ignored packets should be dropped.
 */
	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
/*
 * Create divert sockets. Use only one socket if -p was specified
 * on command line. Otherwise, create separate sockets for
 * outgoing and incoming connnections.
 */
	if (inOutPort) {

		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
		if (divertInOut == -1)
			Quit ("Unable to create divert socket.");

		divertIn  = -1;
		divertOut = -1;
/*
 * Bind socket.
 */

		addr.sin_family		= AF_INET;
		addr.sin_addr.s_addr	= INADDR_ANY;
		addr.sin_port		= inOutPort;

		if (bind (divertInOut,
			  (struct sockaddr*) &addr,
			  sizeof addr) == -1)
			Quit ("Unable to bind divert socket.");
	}
	else {

		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
		if (divertIn == -1)
			Quit ("Unable to create incoming divert socket.");

		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
		if (divertOut == -1)
			Quit ("Unable to create outgoing divert socket.");

		divertInOut = -1;

/*
 * Bind divert sockets.
 */

		addr.sin_family		= AF_INET;
		addr.sin_addr.s_addr	= INADDR_ANY;
		addr.sin_port		= inPort;

		if (bind (divertIn,
			  (struct sockaddr*) &addr,
			  sizeof addr) == -1)
			Quit ("Unable to bind incoming divert socket.");

		addr.sin_family		= AF_INET;
		addr.sin_addr.s_addr	= INADDR_ANY;
		addr.sin_port		= outPort;

		if (bind (divertOut,
			  (struct sockaddr*) &addr,
			  sizeof addr) == -1)
			Quit ("Unable to bind outgoing divert socket.");
	}
/*
 * Create routing socket if interface name specified and in dynamic mode.
 */
	routeSock = -1;
	if (ifName) {
		if (dynamicMode) {

			routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
			if (routeSock == -1)
				Quit ("Unable to create routing info socket.");

			assignAliasAddr = 1;
		}
		else
			SetAliasAddressFromIfName (ifName);
	}
/*
 * Create socket for sending ICMP messages.
 */
	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if (icmpSock == -1)
		Quit ("Unable to create ICMP socket.");

/*
 * And disable reads for the socket, otherwise it slowly fills
 * up with received icmps which we do not use.
 */
	shutdown(icmpSock, SHUT_RD);

/*
 * Become a daemon unless verbose mode was requested.
 */
	if (!verbose)
		DaemonMode ();
/*
 * Catch signals to manage shutdown and
 * refresh of interface address.
 */
	siginterrupt(SIGTERM, 1);
	siginterrupt(SIGHUP, 1);
	signal (SIGTERM, InitiateShutdown);
	signal (SIGHUP, RefreshAddr);
/*
 * Set alias address if it has been given.
 */
	if (aliasAddr.s_addr != INADDR_NONE)
		PacketAliasSetAddress (aliasAddr);
/*
 * We need largest descriptor number for select.
 */

	fdMax = -1;

	if (divertIn > fdMax)
		fdMax = divertIn;

	if (divertOut > fdMax)
		fdMax = divertOut;

	if (divertInOut > fdMax)
		fdMax = divertInOut;

	if (routeSock > fdMax)
		fdMax = routeSock;

	while (running) {

		if (divertInOut != -1 && !ifName && packetSock == -1) {
/*
 * When using only one socket, just call 
 * DoAliasing repeatedly to process packets.
 */
			DoAliasing (divertInOut, DONT_KNOW);
			continue;
		}
/* 
 * Build read mask from socket descriptors to select.
 */
		FD_ZERO (&readMask);
		FD_ZERO (&writeMask);

/*
 * If there is unsent packet in buffer, use select
 * to check when socket comes writable again.
 */
		if (packetSock != -1) {

			FD_SET (packetSock, &writeMask);
		}
		else {
/*
 * No unsent packet exists - safe to check if
 * new ones are available.
 */
			if (divertIn != -1)
				FD_SET (divertIn, &readMask);

			if (divertOut != -1)
				FD_SET (divertOut, &readMask);

			if (divertInOut != -1)
				FD_SET (divertInOut, &readMask);
		}
/*
 * Routing info is processed always.
 */
		if (routeSock != -1)
			FD_SET (routeSock, &readMask);

		if (select (fdMax + 1,
			    &readMask,
			    &writeMask,
			    NULL,
			    NULL) == -1) {

			if (errno == EINTR)
				continue;

			Quit ("Select failed.");
		}

		if (packetSock != -1)
			if (FD_ISSET (packetSock, &writeMask))
				FlushPacketBuffer (packetSock);

		if (divertIn != -1)
			if (FD_ISSET (divertIn, &readMask))
				DoAliasing (divertIn, INPUT);

		if (divertOut != -1)
			if (FD_ISSET (divertOut, &readMask))
				DoAliasing (divertOut, OUTPUT);

		if (divertInOut != -1) 
			if (FD_ISSET (divertInOut, &readMask))
				DoAliasing (divertInOut, DONT_KNOW);

		if (routeSock != -1)
			if (FD_ISSET (routeSock, &readMask))
				HandleRoutingInfo (routeSock);
	}

	if (background)
		unlink (PIDFILE);

	return 0;
}
Exemple #2
0
static void DoAliasing (int fd, int direction)
{
	int			bytes;
	int			origBytes;
	int			status;
	int			addrSize;
	struct ip*		ip;

	if (assignAliasAddr) {

		SetAliasAddressFromIfName (ifName);
		assignAliasAddr = 0;
	}
/*
 * Get packet from socket.
 */
	addrSize  = sizeof packetAddr;
	origBytes = recvfrom (fd,
			      packetBuf,
			      sizeof packetBuf,
			      0,
			      (struct sockaddr*) &packetAddr,
			      &addrSize);

	if (origBytes == -1) {

		if (errno != EINTR)
			Warn ("read from divert socket failed");

		return;
	}
/*
 * This is a IP packet.
 */
	ip = (struct ip*) packetBuf;
	if (direction == DONT_KNOW) {
		if (packetAddr.sin_addr.s_addr == INADDR_ANY)
			direction = OUTPUT;
		else
			direction = INPUT;
	}

	if (verbose) {
/*
 * Print packet direction and protocol type.
 */
		printf (direction == OUTPUT ? "Out " : "In  ");

		switch (ip->ip_p) {
		case IPPROTO_TCP:
			printf ("[TCP]  ");
			break;

		case IPPROTO_UDP:
			printf ("[UDP]  ");
			break;

		case IPPROTO_ICMP:
			printf ("[ICMP] ");
			break;

		default:
			printf ("[%d]    ", ip->ip_p);
			break;
		}
/*
 * Print addresses.
 */
		PrintPacket (ip);
	}

	if (direction == OUTPUT) {
/*
 * Outgoing packets. Do aliasing.
 */
		PacketAliasOut (packetBuf, IP_MAXPACKET);
	}
	else {

/*
 * Do aliasing.
 */	
		status = PacketAliasIn (packetBuf, IP_MAXPACKET);
		if (status == PKT_ALIAS_IGNORED &&
		    dropIgnoredIncoming) {

			if (verbose)
				printf (" dropped.\n");

			if (logDropped)
				SyslogPacket (ip, LOG_WARNING, "denied");

			return;
		}
	}
/*
 * Length might have changed during aliasing.
 */
	bytes = ntohs (ip->ip_len);
/*
 * Update alias overhead size for outgoing packets.
 */
	if (direction == OUTPUT &&
	    bytes - origBytes > aliasOverhead)
		aliasOverhead = bytes - origBytes;

	if (verbose) {
		
/*
 * Print addresses after aliasing.
 */
		printf (" aliased to\n");
		printf ("           ");
		PrintPacket (ip);
		printf ("\n");
	}

	packetLen  	= bytes;
	packetSock 	= fd;
	packetDirection = direction;

	FlushPacketBuffer (fd);
}
Exemple #3
0
static void
DoAliasing(int fd, int direction)
{
	int			bytes;
	int			origBytes;
	char			buf[IP_MAXPACKET];
	struct sockaddr_in	addr;
	int			wrote;
	int			status;
	int			addrSize;
	struct ip*		ip;
	char			msgBuf[80];

	if (assignAliasAddr) {
		SetAliasAddressFromIfName(ifName);
		assignAliasAddr = 0;
	}
/*
 * Get packet from socket.
 */
	addrSize  = sizeof addr;
	origBytes = recvfrom(fd,
			     buf,
			     sizeof buf,
			     0,
			     (struct sockaddr *)&addr,
			     &addrSize);

	if (origBytes == -1) {
		if (errno != EINTR)
			Warn("read from divert socket failed");

		return;
	}
/*
 * This is a IP packet.
 */
	ip = (struct ip *)buf;
	if (direction == DONT_KNOW) {
		if (addr.sin_addr.s_addr == INADDR_ANY)
			direction = OUTPUT;
		else
			direction = INPUT;
	}

	if (verbose) {
/*
 * Print packet direction and protocol type.
 */
		printf(direction == OUTPUT ? "Out " : "In  ");

		switch (ip->ip_p) {
		case IPPROTO_TCP:
			printf("[TCP]  ");
			break;

		case IPPROTO_UDP:
			printf("[UDP]  ");
			break;

		case IPPROTO_ICMP:
			printf("[ICMP] ");
			break;

		default:
			printf("[%d]	", ip->ip_p);
			break;
		}
/*
 * Print addresses.
 */
		PrintPacket(ip);
	}

	if (direction == OUTPUT) {
/*
 * Outgoing packets. Do aliasing.
 */
		PacketAliasOut(buf, IP_MAXPACKET);
	} else {
/*
 * Do aliasing.
 */
		status = PacketAliasIn(buf, IP_MAXPACKET);
		if (status == PKT_ALIAS_IGNORED &&
		    dropIgnoredIncoming) {
			if (verbose)
				printf(" dropped.\n");

			if (logDropped)
				SyslogPacket(ip, LOG_WARNING, "denied");

			return;
		}
	}
/*
 * Length might have changed during aliasing.
 */
	bytes = ntohs(ip->ip_len);
/*
 * Update alias overhead size for outgoing packets.
 */
	if (direction == OUTPUT &&
	    bytes - origBytes > aliasOverhead)
		aliasOverhead = bytes - origBytes;

	if (verbose) {
/*
 * Print addresses after aliasing.
 */
		printf(" aliased to\n");
		printf("	   ");
		PrintPacket(ip);
		printf("\n");
	}

/*
 * Put packet back for processing.
 */
	wrote = sendto(fd,
		       buf,
		       bytes,
		       0,
		       (struct sockaddr *)&addr,
		       sizeof addr);

	if (wrote != bytes) {
		if (errno == EMSGSIZE) {
			if (direction == OUTPUT &&
			    ifMTU != -1)
				SendNeedFragIcmp(icmpSock,
						 (struct ip *)buf,
						 ifMTU - aliasOverhead);
		} else if (errno == EACCES && logIpfwDenied) {
			sprintf(msgBuf, "failed to write packet back");
			Warn(msgBuf);
		}
	}
}