xref: /freebsd/sys/netinet/libalias/alias_proxy.c (revision 9fa0fd268273d90e765d9ebfe0be87ea4d64e138)
1f987e1bdSBrian Somers /*-
2e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3f987e1bdSBrian Somers  * All rights reserved.
4f987e1bdSBrian Somers  *
5f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
6f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
7f987e1bdSBrian Somers  * are met:
8f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
9f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
10f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
12f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
13f987e1bdSBrian Somers  *
14f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24f987e1bdSBrian Somers  * SUCH DAMAGE.
25f987e1bdSBrian Somers  */
26f987e1bdSBrian Somers 
27e2505aa6SMatthew Dillon #include <sys/cdefs.h>
28e2505aa6SMatthew Dillon __FBSDID("$FreeBSD$");
29e2505aa6SMatthew Dillon 
307d96f4efSBrian Somers /* file: alias_proxy.c
317d96f4efSBrian Somers 
327d96f4efSBrian Somers     This file encapsulates special operations related to transparent
337d96f4efSBrian Somers     proxy redirection.  This is where packets with a particular destination,
347d96f4efSBrian Somers     usually tcp port 80, are redirected to a proxy server.
357d96f4efSBrian Somers 
367d96f4efSBrian Somers     When packets are proxied, the destination address and port are
377d96f4efSBrian Somers     modified.  In certain cases, it is necessary to somehow encode
387d96f4efSBrian Somers     the original address/port info into the packet.  Two methods are
397d96f4efSBrian Somers     presently supported: addition of a [DEST addr port] string at the
409d5abbddSJens Schweikhardt     beginning of a tcp stream, or inclusion of an optional field
417d96f4efSBrian Somers     in the IP header.
427d96f4efSBrian Somers 
437d96f4efSBrian Somers     There is one public API function:
447d96f4efSBrian Somers 
457d96f4efSBrian Somers 	PacketAliasProxyRule()    -- Adds and deletes proxy
467d96f4efSBrian Somers 				     rules.
477d96f4efSBrian Somers 
487d96f4efSBrian Somers     Rules are stored in a linear linked list, so lookup efficiency
497d96f4efSBrian Somers     won't be too good for large lists.
507d96f4efSBrian Somers 
517d96f4efSBrian Somers 
527d96f4efSBrian Somers     Initial development: April, 1998 (cjm)
537d96f4efSBrian Somers */
547d96f4efSBrian Somers 
557d96f4efSBrian Somers 
567d96f4efSBrian Somers /* System includes */
577d96f4efSBrian Somers #include <ctype.h>
587d96f4efSBrian Somers #include <stdio.h>
597d96f4efSBrian Somers #include <stdlib.h>
607d96f4efSBrian Somers #include <string.h>
617d96f4efSBrian Somers #include <netdb.h>
627d96f4efSBrian Somers 
637d96f4efSBrian Somers #include <sys/types.h>
647d96f4efSBrian Somers #include <sys/socket.h>
657d96f4efSBrian Somers 
667d96f4efSBrian Somers /* BSD IPV4 includes */
677d96f4efSBrian Somers #include <netinet/in_systm.h>
687d96f4efSBrian Somers #include <netinet/in.h>
697d96f4efSBrian Somers #include <netinet/ip.h>
707d96f4efSBrian Somers #include <netinet/tcp.h>
717d96f4efSBrian Somers 
727d96f4efSBrian Somers #include <arpa/inet.h>
737d96f4efSBrian Somers 
747d96f4efSBrian Somers #include "alias_local.h"	/* Functions used by alias*.c */
757d96f4efSBrian Somers #include "alias.h"		/* Public API functions for libalias */
767d96f4efSBrian Somers 
777d96f4efSBrian Somers 
787d96f4efSBrian Somers 
797d96f4efSBrian Somers /*
807d96f4efSBrian Somers     Data structures
817d96f4efSBrian Somers  */
827d96f4efSBrian Somers 
837d96f4efSBrian Somers /*
847d96f4efSBrian Somers  * A linked list of arbitrary length, based on struct proxy_entry is
857d96f4efSBrian Somers  * used to store proxy rules.
867d96f4efSBrian Somers  */
87f0f93429SDag-Erling Smørgrav struct proxy_entry {
885e289f9eSPoul-Henning Kamp 	struct libalias *la;
897d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
907d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
917d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
927d96f4efSBrian Somers 	int		rule_index;
937d96f4efSBrian Somers 	int		proxy_type;
947d96f4efSBrian Somers 	u_char		proto;
957d96f4efSBrian Somers 	u_short		proxy_port;
967d96f4efSBrian Somers 	u_short		server_port;
977d96f4efSBrian Somers 
987d96f4efSBrian Somers 	struct in_addr	server_addr;
997d96f4efSBrian Somers 
1007d96f4efSBrian Somers 	struct in_addr	src_addr;
1017d96f4efSBrian Somers 	struct in_addr	src_mask;
1027d96f4efSBrian Somers 
1037d96f4efSBrian Somers 	struct in_addr	dst_addr;
1047d96f4efSBrian Somers 	struct in_addr	dst_mask;
1057d96f4efSBrian Somers 
1067d96f4efSBrian Somers 	struct proxy_entry *next;
1077d96f4efSBrian Somers 	struct proxy_entry *last;
1087d96f4efSBrian Somers };
1097d96f4efSBrian Somers 
1107d96f4efSBrian Somers 
1117d96f4efSBrian Somers 
1127d96f4efSBrian Somers /*
1137d96f4efSBrian Somers     File scope variables
1147d96f4efSBrian Somers */
1157d96f4efSBrian Somers 
1167d96f4efSBrian Somers 
1177d96f4efSBrian Somers 
1187d96f4efSBrian Somers /* Local (static) functions:
1197d96f4efSBrian Somers 
1207d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
1217d96f4efSBrian Somers 				masks from integer (1-32) specification.
1227d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
1237d96f4efSBrian Somers 				to IP address
1247d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
1257d96f4efSBrian Somers 				to port number
1267d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1277d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1287d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1297d96f4efSBrian Somers 				having a certain rule number.
1307d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1317d96f4efSBrian Somers 				of a TCP stream.
1327d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1337d96f4efSBrian Somers 				destination of a proxied IP packet
1347d96f4efSBrian Somers */
1357d96f4efSBrian Somers 
1367d96f4efSBrian Somers static int	IpMask(int, struct in_addr *);
1377d96f4efSBrian Somers static int	IpAddr(char *, struct in_addr *);
1387d96f4efSBrian Somers static int	IpPort(char *, int, int *);
1395e289f9eSPoul-Henning Kamp static void	RuleAdd(struct libalias *la, struct proxy_entry *);
1407d96f4efSBrian Somers static void	RuleDelete(struct proxy_entry *);
1415e289f9eSPoul-Henning Kamp static int	RuleNumberDelete(struct libalias *la, int);
1427d96f4efSBrian Somers static void	ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1437d96f4efSBrian Somers static void	ProxyEncodeIpHeader(struct ip *, int);
1447d96f4efSBrian Somers 
1457d96f4efSBrian Somers static int
1467d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
1477d96f4efSBrian Somers {
1487d96f4efSBrian Somers 	int i;
1497d96f4efSBrian Somers 	u_int imask;
1507d96f4efSBrian Somers 
1517d96f4efSBrian Somers 	if (nbits < 0 || nbits > 32)
152ffcb611aSDag-Erling Smørgrav 		return (-1);
1537d96f4efSBrian Somers 
1547d96f4efSBrian Somers 	imask = 0;
1557d96f4efSBrian Somers 	for (i = 0; i < nbits; i++)
1567d96f4efSBrian Somers 		imask = (imask >> 1) + 0x80000000;
1577d96f4efSBrian Somers 	mask->s_addr = htonl(imask);
1587d96f4efSBrian Somers 
159ffcb611aSDag-Erling Smørgrav 	return (0);
1607d96f4efSBrian Somers }
1617d96f4efSBrian Somers 
1627d96f4efSBrian Somers static int
1637d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
1647d96f4efSBrian Somers {
1657d96f4efSBrian Somers 	if (inet_aton(s, addr) == 0)
166ffcb611aSDag-Erling Smørgrav 		return (-1);
1677d96f4efSBrian Somers 	else
168ffcb611aSDag-Erling Smørgrav 		return (0);
1697d96f4efSBrian Somers }
1707d96f4efSBrian Somers 
1717d96f4efSBrian Somers static int
1727d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
1737d96f4efSBrian Somers {
1747d96f4efSBrian Somers 	int n;
1757d96f4efSBrian Somers 
1767d96f4efSBrian Somers 	n = sscanf(s, "%d", port);
177f0f93429SDag-Erling Smørgrav 	if (n != 1) {
1787d96f4efSBrian Somers 		struct servent *se;
1797d96f4efSBrian Somers 
1807d96f4efSBrian Somers 		if (proto == IPPROTO_TCP)
1817d96f4efSBrian Somers 			se = getservbyname(s, "tcp");
1827d96f4efSBrian Somers 		else if (proto == IPPROTO_UDP)
1837d96f4efSBrian Somers 			se = getservbyname(s, "udp");
1847d96f4efSBrian Somers 		else
185ffcb611aSDag-Erling Smørgrav 			return (-1);
1867d96f4efSBrian Somers 
1877d96f4efSBrian Somers 		if (se == NULL)
188ffcb611aSDag-Erling Smørgrav 			return (-1);
1897d96f4efSBrian Somers 
1907d96f4efSBrian Somers 		*port = (u_int) ntohs(se->s_port);
1917d96f4efSBrian Somers 	}
192ffcb611aSDag-Erling Smørgrav 	return (0);
1937d96f4efSBrian Somers }
1947d96f4efSBrian Somers 
1957d96f4efSBrian Somers void
1965e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry)
1977d96f4efSBrian Somers {
1987d96f4efSBrian Somers 	int rule_index;
1997d96f4efSBrian Somers 	struct proxy_entry *ptr;
2007d96f4efSBrian Somers 	struct proxy_entry *ptr_last;
2017d96f4efSBrian Somers 
202f0f93429SDag-Erling Smørgrav 	if (la->proxyList == NULL) {
2035e289f9eSPoul-Henning Kamp 		la->proxyList = entry;
2047d96f4efSBrian Somers 		entry->last = NULL;
2057d96f4efSBrian Somers 		entry->next = NULL;
2067d96f4efSBrian Somers 		return;
2077d96f4efSBrian Somers 	}
2085e289f9eSPoul-Henning Kamp 	entry->la = la;
2097d96f4efSBrian Somers 
2107d96f4efSBrian Somers 	rule_index = entry->rule_index;
2115e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
2127d96f4efSBrian Somers 	ptr_last = NULL;
213f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
214f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index >= rule_index) {
215f0f93429SDag-Erling Smørgrav 			if (ptr_last == NULL) {
2165e289f9eSPoul-Henning Kamp 				entry->next = la->proxyList;
2177d96f4efSBrian Somers 				entry->last = NULL;
2185e289f9eSPoul-Henning Kamp 				la->proxyList->last = entry;
2195e289f9eSPoul-Henning Kamp 				la->proxyList = entry;
2207d96f4efSBrian Somers 				return;
2217d96f4efSBrian Somers 			}
2227d96f4efSBrian Somers 			ptr_last->next = entry;
2237d96f4efSBrian Somers 			ptr->last = entry;
2247d96f4efSBrian Somers 			entry->last = ptr->last;
2257d96f4efSBrian Somers 			entry->next = ptr;
2267d96f4efSBrian Somers 			return;
2277d96f4efSBrian Somers 		}
2287d96f4efSBrian Somers 		ptr_last = ptr;
2297d96f4efSBrian Somers 		ptr = ptr->next;
2307d96f4efSBrian Somers 	}
2317d96f4efSBrian Somers 
2327d96f4efSBrian Somers 	ptr_last->next = entry;
2337d96f4efSBrian Somers 	entry->last = ptr_last;
2347d96f4efSBrian Somers 	entry->next = NULL;
2357d96f4efSBrian Somers }
2367d96f4efSBrian Somers 
2377d96f4efSBrian Somers static void
2387d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
2397d96f4efSBrian Somers {
2405e289f9eSPoul-Henning Kamp 	struct libalias *la;
2415e289f9eSPoul-Henning Kamp 
2425e289f9eSPoul-Henning Kamp 	la = entry->la;
2437d96f4efSBrian Somers 	if (entry->last != NULL)
2447d96f4efSBrian Somers 		entry->last->next = entry->next;
2457d96f4efSBrian Somers 	else
2465e289f9eSPoul-Henning Kamp 		la->proxyList = entry->next;
2477d96f4efSBrian Somers 
2487d96f4efSBrian Somers 	if (entry->next != NULL)
2497d96f4efSBrian Somers 		entry->next->last = entry->last;
2507d96f4efSBrian Somers 
2517d96f4efSBrian Somers 	free(entry);
2527d96f4efSBrian Somers }
2537d96f4efSBrian Somers 
2547d96f4efSBrian Somers static int
2555e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index)
2567d96f4efSBrian Somers {
2577d96f4efSBrian Somers 	int err;
2587d96f4efSBrian Somers 	struct proxy_entry *ptr;
2597d96f4efSBrian Somers 
2607d96f4efSBrian Somers 	err = -1;
2615e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
262f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
2637d96f4efSBrian Somers 		struct proxy_entry *ptr_next;
2647d96f4efSBrian Somers 
2657d96f4efSBrian Somers 		ptr_next = ptr->next;
266f0f93429SDag-Erling Smørgrav 		if (ptr->rule_index == rule_index) {
2677d96f4efSBrian Somers 			err = 0;
2687d96f4efSBrian Somers 			RuleDelete(ptr);
2697d96f4efSBrian Somers 		}
2707d96f4efSBrian Somers 		ptr = ptr_next;
2717d96f4efSBrian Somers 	}
2727d96f4efSBrian Somers 
273ffcb611aSDag-Erling Smørgrav 	return (err);
2747d96f4efSBrian Somers }
2757d96f4efSBrian Somers 
2767d96f4efSBrian Somers static void
277ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(struct alias_link *lnk,
2787d96f4efSBrian Somers     struct ip *pip,
2797d96f4efSBrian Somers     int maxpacketsize)
2807d96f4efSBrian Somers {
2817d96f4efSBrian Somers 	int slen;
2827d96f4efSBrian Somers 	char buffer[40];
2837d96f4efSBrian Somers 	struct tcphdr *tc;
2847d96f4efSBrian Somers 
2857d96f4efSBrian Somers /* Compute pointer to tcp header */
2869fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
2877d96f4efSBrian Somers 
2887d96f4efSBrian Somers /* Don't modify if once already modified */
2897d96f4efSBrian Somers 
290ed01a582SDag-Erling Smørgrav 	if (GetAckModified(lnk))
2917d96f4efSBrian Somers 		return;
2927d96f4efSBrian Somers 
2937d96f4efSBrian Somers /* Translate destination address and port to string form */
2947d96f4efSBrian Somers 	snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
295ed01a582SDag-Erling Smørgrav 	    inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk)));
2967d96f4efSBrian Somers 
2977d96f4efSBrian Somers /* Pad string out to a multiple of two in length */
2987d96f4efSBrian Somers 	slen = strlen(buffer);
299f0f93429SDag-Erling Smørgrav 	switch (slen % 2) {
3007d96f4efSBrian Somers 	case 0:
3017d96f4efSBrian Somers 		strcat(buffer, " \n");
3027d96f4efSBrian Somers 		slen += 2;
3037d96f4efSBrian Somers 		break;
3047d96f4efSBrian Somers 	case 1:
3057d96f4efSBrian Somers 		strcat(buffer, "\n");
3067d96f4efSBrian Somers 		slen += 1;
3077d96f4efSBrian Somers 	}
3087d96f4efSBrian Somers 
3097d96f4efSBrian Somers /* Check for packet overflow */
310ed01a582SDag-Erling Smørgrav 	if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
3117d96f4efSBrian Somers 		return;
3127d96f4efSBrian Somers 
3137d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */
3147d96f4efSBrian Somers 	{
3157d96f4efSBrian Somers 		int dlen;
3167d96f4efSBrian Somers 		int hlen;
3177d96f4efSBrian Somers 		u_char *p;
3187d96f4efSBrian Somers 
3197d96f4efSBrian Somers 		hlen = (pip->ip_hl + tc->th_off) << 2;
3207d96f4efSBrian Somers 		dlen = ntohs(pip->ip_len) - hlen;
3217d96f4efSBrian Somers 
3227d96f4efSBrian Somers /* Modify first packet that has data in it */
3237d96f4efSBrian Somers 
3247d96f4efSBrian Somers 		if (dlen == 0)
3257d96f4efSBrian Somers 			return;
3267d96f4efSBrian Somers 
3277d96f4efSBrian Somers 		p = (char *)pip;
3287d96f4efSBrian Somers 		p += hlen;
3297d96f4efSBrian Somers 
3307d96f4efSBrian Somers 		memmove(p + slen, p, dlen);
3317d96f4efSBrian Somers 		memcpy(p, buffer, slen);
3327d96f4efSBrian Somers 	}
3337d96f4efSBrian Somers 
3347d96f4efSBrian Somers /* Save information about modfied sequence number */
3357d96f4efSBrian Somers 	{
3367d96f4efSBrian Somers 		int delta;
3377d96f4efSBrian Somers 
338ed01a582SDag-Erling Smørgrav 		SetAckModified(lnk);
339ed01a582SDag-Erling Smørgrav 		delta = GetDeltaSeqOut(pip, lnk);
340ed01a582SDag-Erling Smørgrav 		AddSeq(pip, lnk, delta + slen);
3417d96f4efSBrian Somers 	}
3427d96f4efSBrian Somers 
3437d96f4efSBrian Somers /* Update IP header packet length and checksum */
3447d96f4efSBrian Somers 	{
3457d96f4efSBrian Somers 		int accumulate;
3467d96f4efSBrian Somers 
3477d96f4efSBrian Somers 		accumulate = pip->ip_len;
3487d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + slen);
3497d96f4efSBrian Somers 		accumulate -= pip->ip_len;
3507d96f4efSBrian Somers 
3517d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
3527d96f4efSBrian Somers 	}
3537d96f4efSBrian Somers 
3547d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have
3557d96f4efSBrian Somers    already changed. */
3567d96f4efSBrian Somers 
3577d96f4efSBrian Somers 	tc->th_sum = 0;
3587d96f4efSBrian Somers 	tc->th_sum = TcpChecksum(pip);
3597d96f4efSBrian Somers }
3607d96f4efSBrian Somers 
3617d96f4efSBrian Somers static void
3627d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip,
3637d96f4efSBrian Somers     int maxpacketsize)
3647d96f4efSBrian Somers {
3657d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
3667d96f4efSBrian Somers #define OPTION_LEN_INT16  4
3677d96f4efSBrian Somers #define OPTION_LEN_INT32  2
3687d96f4efSBrian Somers 	u_char option[OPTION_LEN_BYTES];
3697d96f4efSBrian Somers 
3704c32f5d2SBrian Somers #ifdef DEBUG
3717d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
3727d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
3734c32f5d2SBrian Somers #endif
3747d96f4efSBrian Somers 
375ed01a582SDag-Erling Smørgrav 	(void)maxpacketsize;
376ed01a582SDag-Erling Smørgrav 
3777d96f4efSBrian Somers /* Check to see that there is room to add an IP option */
3787d96f4efSBrian Somers 	if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
3797d96f4efSBrian Somers 		return;
3807d96f4efSBrian Somers 
3817d96f4efSBrian Somers /* Build option and copy into packet */
3827d96f4efSBrian Somers 	{
3837d96f4efSBrian Somers 		u_char *ptr;
3847d96f4efSBrian Somers 		struct tcphdr *tc;
3857d96f4efSBrian Somers 
3867d96f4efSBrian Somers 		ptr = (u_char *) pip;
3877d96f4efSBrian Somers 		ptr += 20;
3887d96f4efSBrian Somers 		memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
3897d96f4efSBrian Somers 
3907d96f4efSBrian Somers 		option[0] = 0x64;	/* class: 3 (reserved), option 4 */
3917d96f4efSBrian Somers 		option[1] = OPTION_LEN_BYTES;
3927d96f4efSBrian Somers 
3937d96f4efSBrian Somers 		memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
3947d96f4efSBrian Somers 
3959fa0fd26SDag-Erling Smørgrav 		tc = (struct tcphdr *)ip_next(pip);
3967d96f4efSBrian Somers 		memcpy(&option[6], (u_char *) & tc->th_sport, 2);
3977d96f4efSBrian Somers 
3987d96f4efSBrian Somers 		memcpy(ptr, option, 8);
3997d96f4efSBrian Somers 	}
4007d96f4efSBrian Somers 
4017d96f4efSBrian Somers /* Update checksum, header length and packet length */
4027d96f4efSBrian Somers 	{
4037d96f4efSBrian Somers 		int i;
4047d96f4efSBrian Somers 		int accumulate;
4057d96f4efSBrian Somers 		u_short *sptr;
4067d96f4efSBrian Somers 
4077d96f4efSBrian Somers 		sptr = (u_short *) option;
4087d96f4efSBrian Somers 		accumulate = 0;
4097d96f4efSBrian Somers 		for (i = 0; i < OPTION_LEN_INT16; i++)
4107d96f4efSBrian Somers 			accumulate -= *(sptr++);
4117d96f4efSBrian Somers 
4127d96f4efSBrian Somers 		sptr = (u_short *) pip;
4137d96f4efSBrian Somers 		accumulate += *sptr;
4147d96f4efSBrian Somers 		pip->ip_hl += OPTION_LEN_INT32;
4157d96f4efSBrian Somers 		accumulate -= *sptr;
4167d96f4efSBrian Somers 
4177d96f4efSBrian Somers 		accumulate += pip->ip_len;
4187d96f4efSBrian Somers 		pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
4197d96f4efSBrian Somers 		accumulate -= pip->ip_len;
4207d96f4efSBrian Somers 
4217d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4227d96f4efSBrian Somers 	}
4237d96f4efSBrian Somers #undef OPTION_LEN_BYTES
4247d96f4efSBrian Somers #undef OPTION_LEN_INT16
4257d96f4efSBrian Somers #undef OPTION_LEN_INT32
4264c32f5d2SBrian Somers #ifdef DEBUG
4277d96f4efSBrian Somers 	fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
4287d96f4efSBrian Somers 	fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
4294c32f5d2SBrian Somers #endif
4307d96f4efSBrian Somers }
4317d96f4efSBrian Somers 
4327d96f4efSBrian Somers 
4337d96f4efSBrian Somers /* Functions by other packet alias source files
4347d96f4efSBrian Somers 
4357d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
4367d96f4efSBrian Somers 			    be proxied.
4377d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
4387d96f4efSBrian Somers 			    for a packet which is to be redirected to
4397d96f4efSBrian Somers 			    a proxy server.
4407d96f4efSBrian Somers */
4417d96f4efSBrian Somers 
4427d96f4efSBrian Somers int
4435e289f9eSPoul-Henning Kamp ProxyCheck(struct libalias *la, struct ip *pip,
4447d96f4efSBrian Somers     struct in_addr *proxy_server_addr,
4457d96f4efSBrian Somers     u_short * proxy_server_port)
4467d96f4efSBrian Somers {
4477d96f4efSBrian Somers 	u_short dst_port;
4487d96f4efSBrian Somers 	struct in_addr src_addr;
4497d96f4efSBrian Somers 	struct in_addr dst_addr;
4507d96f4efSBrian Somers 	struct proxy_entry *ptr;
4517d96f4efSBrian Somers 
4527d96f4efSBrian Somers 	src_addr = pip->ip_src;
4537d96f4efSBrian Somers 	dst_addr = pip->ip_dst;
4549fa0fd26SDag-Erling Smørgrav 	dst_port = ((struct tcphdr *)ip_next(pip))
4557d96f4efSBrian Somers 	    ->th_dport;
4567d96f4efSBrian Somers 
4575e289f9eSPoul-Henning Kamp 	ptr = la->proxyList;
458f0f93429SDag-Erling Smørgrav 	while (ptr != NULL) {
4597d96f4efSBrian Somers 		u_short proxy_port;
4607d96f4efSBrian Somers 
4617d96f4efSBrian Somers 		proxy_port = ptr->proxy_port;
4627d96f4efSBrian Somers 		if ((dst_port == proxy_port || proxy_port == 0)
4637d96f4efSBrian Somers 		    && pip->ip_p == ptr->proto
464f0f93429SDag-Erling Smørgrav 		    && src_addr.s_addr != ptr->server_addr.s_addr) {
4657d96f4efSBrian Somers 			struct in_addr src_addr_masked;
4667d96f4efSBrian Somers 			struct in_addr dst_addr_masked;
4677d96f4efSBrian Somers 
4687d96f4efSBrian Somers 			src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
4697d96f4efSBrian Somers 			dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
4707d96f4efSBrian Somers 
4717d96f4efSBrian Somers 			if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
472f0f93429SDag-Erling Smørgrav 			    && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
4737d96f4efSBrian Somers 				if ((*proxy_server_port = ptr->server_port) == 0)
4747d96f4efSBrian Somers 					*proxy_server_port = dst_port;
4757d96f4efSBrian Somers 				*proxy_server_addr = ptr->server_addr;
476ffcb611aSDag-Erling Smørgrav 				return (ptr->proxy_type);
4777d96f4efSBrian Somers 			}
4787d96f4efSBrian Somers 		}
4797d96f4efSBrian Somers 		ptr = ptr->next;
4807d96f4efSBrian Somers 	}
4817d96f4efSBrian Somers 
482ffcb611aSDag-Erling Smørgrav 	return (0);
4837d96f4efSBrian Somers }
4847d96f4efSBrian Somers 
4857d96f4efSBrian Somers void
486ed01a582SDag-Erling Smørgrav ProxyModify(struct libalias *la, struct alias_link *lnk,
4877d96f4efSBrian Somers     struct ip *pip,
4887d96f4efSBrian Somers     int maxpacketsize,
4897d96f4efSBrian Somers     int proxy_type)
4907d96f4efSBrian Somers {
491ed01a582SDag-Erling Smørgrav 
492ed01a582SDag-Erling Smørgrav 	(void)la;
493ed01a582SDag-Erling Smørgrav 
494f0f93429SDag-Erling Smørgrav 	switch (proxy_type) {
4957d96f4efSBrian Somers 		case PROXY_TYPE_ENCODE_IPHDR:
4967d96f4efSBrian Somers 		ProxyEncodeIpHeader(pip, maxpacketsize);
4977d96f4efSBrian Somers 		break;
4987d96f4efSBrian Somers 
4997d96f4efSBrian Somers 	case PROXY_TYPE_ENCODE_TCPSTREAM:
500ed01a582SDag-Erling Smørgrav 		ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
5017d96f4efSBrian Somers 		break;
5027d96f4efSBrian Somers 	}
5037d96f4efSBrian Somers }
5047d96f4efSBrian Somers 
5057d96f4efSBrian Somers 
5067d96f4efSBrian Somers /*
5077d96f4efSBrian Somers     Public API functions
5087d96f4efSBrian Somers */
5097d96f4efSBrian Somers 
5107d96f4efSBrian Somers int
5115e289f9eSPoul-Henning Kamp LibAliasProxyRule(struct libalias *la, const char *cmd)
5127d96f4efSBrian Somers {
5137d96f4efSBrian Somers /*
5147d96f4efSBrian Somers  * This function takes command strings of the form:
5157d96f4efSBrian Somers  *
5167d96f4efSBrian Somers  *   server <addr>[:<port>]
5177d96f4efSBrian Somers  *   [port <port>]
5187d96f4efSBrian Somers  *   [rule n]
5197d96f4efSBrian Somers  *   [proto tcp|udp]
5207d96f4efSBrian Somers  *   [src <addr>[/n]]
5217d96f4efSBrian Somers  *   [dst <addr>[/n]]
5227d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
5237d96f4efSBrian Somers  *
5247d96f4efSBrian Somers  *   delete <rule number>
5257d96f4efSBrian Somers  *
5267d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
5277d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
5287d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
5297d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
5307d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
5317d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
5327d96f4efSBrian Somers  * others.
5337d96f4efSBrian Somers  */
5347d96f4efSBrian Somers 	int i, n, len;
5357d96f4efSBrian Somers 	int cmd_len;
5367d96f4efSBrian Somers 	int token_count;
5377d96f4efSBrian Somers 	int state;
5387d96f4efSBrian Somers 	char *token;
5397d96f4efSBrian Somers 	char buffer[256];
5407d96f4efSBrian Somers 	char str_port[sizeof(buffer)];
5417d96f4efSBrian Somers 	char str_server_port[sizeof(buffer)];
542d9e630b5SAndrey A. Chernov 	char *res = buffer;
5437d96f4efSBrian Somers 
5447d96f4efSBrian Somers 	int rule_index;
5457d96f4efSBrian Somers 	int proto;
5467d96f4efSBrian Somers 	int proxy_type;
5477d96f4efSBrian Somers 	int proxy_port;
5487d96f4efSBrian Somers 	int server_port;
5497d96f4efSBrian Somers 	struct in_addr server_addr;
5507d96f4efSBrian Somers 	struct in_addr src_addr, src_mask;
5517d96f4efSBrian Somers 	struct in_addr dst_addr, dst_mask;
5527d96f4efSBrian Somers 	struct proxy_entry *proxy_entry;
5537d96f4efSBrian Somers 
5547d96f4efSBrian Somers /* Copy command line into a buffer */
5554834b77dSBrian Somers 	cmd += strspn(cmd, " \t");
5567d96f4efSBrian Somers 	cmd_len = strlen(cmd);
557ed01a582SDag-Erling Smørgrav 	if (cmd_len > (int)(sizeof(buffer) - 1))
558ffcb611aSDag-Erling Smørgrav 		return (-1);
5597d96f4efSBrian Somers 	strcpy(buffer, cmd);
5607d96f4efSBrian Somers 
5617d96f4efSBrian Somers /* Convert to lower case */
5627d96f4efSBrian Somers 	len = strlen(buffer);
5637d96f4efSBrian Somers 	for (i = 0; i < len; i++)
564d9e630b5SAndrey A. Chernov 		buffer[i] = tolower((unsigned char)buffer[i]);
5657d96f4efSBrian Somers 
5667d96f4efSBrian Somers /* Set default proxy type */
5677d96f4efSBrian Somers 
5687d96f4efSBrian Somers /* Set up default values */
5697d96f4efSBrian Somers 	rule_index = 0;
5707d96f4efSBrian Somers 	proxy_type = PROXY_TYPE_ENCODE_NONE;
5717d96f4efSBrian Somers 	proto = IPPROTO_TCP;
5727d96f4efSBrian Somers 	proxy_port = 0;
5737d96f4efSBrian Somers 	server_addr.s_addr = 0;
5747d96f4efSBrian Somers 	server_port = 0;
5757d96f4efSBrian Somers 	src_addr.s_addr = 0;
5767d96f4efSBrian Somers 	IpMask(0, &src_mask);
5777d96f4efSBrian Somers 	dst_addr.s_addr = 0;
5787d96f4efSBrian Somers 	IpMask(0, &dst_mask);
5797d96f4efSBrian Somers 
5807d96f4efSBrian Somers 	str_port[0] = 0;
5817d96f4efSBrian Somers 	str_server_port[0] = 0;
5827d96f4efSBrian Somers 
5837d96f4efSBrian Somers /* Parse command string with state machine */
5847d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
5857d96f4efSBrian Somers #define STATE_READ_TYPE       1
5867d96f4efSBrian Somers #define STATE_READ_PORT       2
5877d96f4efSBrian Somers #define STATE_READ_SERVER     3
5887d96f4efSBrian Somers #define STATE_READ_RULE       4
5897d96f4efSBrian Somers #define STATE_READ_DELETE     5
5907d96f4efSBrian Somers #define STATE_READ_PROTO      6
5917d96f4efSBrian Somers #define STATE_READ_SRC        7
5927d96f4efSBrian Somers #define STATE_READ_DST        8
5937d96f4efSBrian Somers 	state = STATE_READ_KEYWORD;
594d9e630b5SAndrey A. Chernov 	token = strsep(&res, " \t");
5957d96f4efSBrian Somers 	token_count = 0;
596f0f93429SDag-Erling Smørgrav 	while (token != NULL) {
5977d96f4efSBrian Somers 		token_count++;
598f0f93429SDag-Erling Smørgrav 		switch (state) {
5997d96f4efSBrian Somers 		case STATE_READ_KEYWORD:
6007d96f4efSBrian Somers 			if (strcmp(token, "type") == 0)
6017d96f4efSBrian Somers 				state = STATE_READ_TYPE;
6027d96f4efSBrian Somers 			else if (strcmp(token, "port") == 0)
6037d96f4efSBrian Somers 				state = STATE_READ_PORT;
6047d96f4efSBrian Somers 			else if (strcmp(token, "server") == 0)
6057d96f4efSBrian Somers 				state = STATE_READ_SERVER;
6067d96f4efSBrian Somers 			else if (strcmp(token, "rule") == 0)
6077d96f4efSBrian Somers 				state = STATE_READ_RULE;
6087d96f4efSBrian Somers 			else if (strcmp(token, "delete") == 0)
6097d96f4efSBrian Somers 				state = STATE_READ_DELETE;
6107d96f4efSBrian Somers 			else if (strcmp(token, "proto") == 0)
6117d96f4efSBrian Somers 				state = STATE_READ_PROTO;
6127d96f4efSBrian Somers 			else if (strcmp(token, "src") == 0)
6137d96f4efSBrian Somers 				state = STATE_READ_SRC;
6147d96f4efSBrian Somers 			else if (strcmp(token, "dst") == 0)
6157d96f4efSBrian Somers 				state = STATE_READ_DST;
6167d96f4efSBrian Somers 			else
617ffcb611aSDag-Erling Smørgrav 				return (-1);
6187d96f4efSBrian Somers 			break;
6197d96f4efSBrian Somers 
6207d96f4efSBrian Somers 		case STATE_READ_TYPE:
6217d96f4efSBrian Somers 			if (strcmp(token, "encode_ip_hdr") == 0)
6227d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_IPHDR;
6237d96f4efSBrian Somers 			else if (strcmp(token, "encode_tcp_stream") == 0)
6247d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
6257d96f4efSBrian Somers 			else if (strcmp(token, "no_encode") == 0)
6267d96f4efSBrian Somers 				proxy_type = PROXY_TYPE_ENCODE_NONE;
6277d96f4efSBrian Somers 			else
628ffcb611aSDag-Erling Smørgrav 				return (-1);
6297d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6307d96f4efSBrian Somers 			break;
6317d96f4efSBrian Somers 
6327d96f4efSBrian Somers 		case STATE_READ_PORT:
6337d96f4efSBrian Somers 			strcpy(str_port, token);
6347d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6357d96f4efSBrian Somers 			break;
6367d96f4efSBrian Somers 
6377d96f4efSBrian Somers 		case STATE_READ_SERVER:
6387d96f4efSBrian Somers 			{
6397d96f4efSBrian Somers 				int err;
6407d96f4efSBrian Somers 				char *p;
6417d96f4efSBrian Somers 				char s[sizeof(buffer)];
6427d96f4efSBrian Somers 
6437d96f4efSBrian Somers 				p = token;
6447d96f4efSBrian Somers 				while (*p != ':' && *p != 0)
6457d96f4efSBrian Somers 					p++;
6467d96f4efSBrian Somers 
647f0f93429SDag-Erling Smørgrav 				if (*p != ':') {
6487d96f4efSBrian Somers 					err = IpAddr(token, &server_addr);
6497d96f4efSBrian Somers 					if (err)
650ffcb611aSDag-Erling Smørgrav 						return (-1);
651f0f93429SDag-Erling Smørgrav 				} else {
6527d96f4efSBrian Somers 					*p = ' ';
6537d96f4efSBrian Somers 
6547d96f4efSBrian Somers 					n = sscanf(token, "%s %s", s, str_server_port);
6557d96f4efSBrian Somers 					if (n != 2)
656ffcb611aSDag-Erling Smørgrav 						return (-1);
6577d96f4efSBrian Somers 
6587d96f4efSBrian Somers 					err = IpAddr(s, &server_addr);
6597d96f4efSBrian Somers 					if (err)
660ffcb611aSDag-Erling Smørgrav 						return (-1);
6617d96f4efSBrian Somers 				}
6627d96f4efSBrian Somers 			}
6637d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6647d96f4efSBrian Somers 			break;
6657d96f4efSBrian Somers 
6667d96f4efSBrian Somers 		case STATE_READ_RULE:
6677d96f4efSBrian Somers 			n = sscanf(token, "%d", &rule_index);
6687d96f4efSBrian Somers 			if (n != 1 || rule_index < 0)
669ffcb611aSDag-Erling Smørgrav 				return (-1);
6707d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6717d96f4efSBrian Somers 			break;
6727d96f4efSBrian Somers 
6737d96f4efSBrian Somers 		case STATE_READ_DELETE:
6747d96f4efSBrian Somers 			{
6757d96f4efSBrian Somers 				int err;
6767d96f4efSBrian Somers 				int rule_to_delete;
6777d96f4efSBrian Somers 
6787d96f4efSBrian Somers 				if (token_count != 2)
679ffcb611aSDag-Erling Smørgrav 					return (-1);
6807d96f4efSBrian Somers 
6817d96f4efSBrian Somers 				n = sscanf(token, "%d", &rule_to_delete);
6827d96f4efSBrian Somers 				if (n != 1)
683ffcb611aSDag-Erling Smørgrav 					return (-1);
6845e289f9eSPoul-Henning Kamp 				err = RuleNumberDelete(la, rule_to_delete);
6857d96f4efSBrian Somers 				if (err)
686ffcb611aSDag-Erling Smørgrav 					return (-1);
687ffcb611aSDag-Erling Smørgrav 				return (0);
6887d96f4efSBrian Somers 			}
6897d96f4efSBrian Somers 
6907d96f4efSBrian Somers 		case STATE_READ_PROTO:
6917d96f4efSBrian Somers 			if (strcmp(token, "tcp") == 0)
6927d96f4efSBrian Somers 				proto = IPPROTO_TCP;
6937d96f4efSBrian Somers 			else if (strcmp(token, "udp") == 0)
6947d96f4efSBrian Somers 				proto = IPPROTO_UDP;
6957d96f4efSBrian Somers 			else
696ffcb611aSDag-Erling Smørgrav 				return (-1);
6977d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
6987d96f4efSBrian Somers 			break;
6997d96f4efSBrian Somers 
7007d96f4efSBrian Somers 		case STATE_READ_SRC:
7017d96f4efSBrian Somers 		case STATE_READ_DST:
7027d96f4efSBrian Somers 			{
7037d96f4efSBrian Somers 				int err;
7047d96f4efSBrian Somers 				char *p;
7057d96f4efSBrian Somers 				struct in_addr mask;
7067d96f4efSBrian Somers 				struct in_addr addr;
7077d96f4efSBrian Somers 
7087d96f4efSBrian Somers 				p = token;
7097d96f4efSBrian Somers 				while (*p != '/' && *p != 0)
7107d96f4efSBrian Somers 					p++;
7117d96f4efSBrian Somers 
712f0f93429SDag-Erling Smørgrav 				if (*p != '/') {
7137d96f4efSBrian Somers 					IpMask(32, &mask);
7147d96f4efSBrian Somers 					err = IpAddr(token, &addr);
7157d96f4efSBrian Somers 					if (err)
716ffcb611aSDag-Erling Smørgrav 						return (-1);
717f0f93429SDag-Erling Smørgrav 				} else {
7187d96f4efSBrian Somers 					int nbits;
7197d96f4efSBrian Somers 					char s[sizeof(buffer)];
7207d96f4efSBrian Somers 
7217d96f4efSBrian Somers 					*p = ' ';
7227d96f4efSBrian Somers 					n = sscanf(token, "%s %d", s, &nbits);
7237d96f4efSBrian Somers 					if (n != 2)
724ffcb611aSDag-Erling Smørgrav 						return (-1);
7257d96f4efSBrian Somers 
7267d96f4efSBrian Somers 					err = IpAddr(s, &addr);
7277d96f4efSBrian Somers 					if (err)
728ffcb611aSDag-Erling Smørgrav 						return (-1);
7297d96f4efSBrian Somers 
7307d96f4efSBrian Somers 					err = IpMask(nbits, &mask);
7317d96f4efSBrian Somers 					if (err)
732ffcb611aSDag-Erling Smørgrav 						return (-1);
7337d96f4efSBrian Somers 				}
7347d96f4efSBrian Somers 
735f0f93429SDag-Erling Smørgrav 				if (state == STATE_READ_SRC) {
7367d96f4efSBrian Somers 					src_addr = addr;
7377d96f4efSBrian Somers 					src_mask = mask;
738f0f93429SDag-Erling Smørgrav 				} else {
7397d96f4efSBrian Somers 					dst_addr = addr;
7407d96f4efSBrian Somers 					dst_mask = mask;
7417d96f4efSBrian Somers 				}
7427d96f4efSBrian Somers 			}
7437d96f4efSBrian Somers 			state = STATE_READ_KEYWORD;
7447d96f4efSBrian Somers 			break;
7457d96f4efSBrian Somers 
7467d96f4efSBrian Somers 		default:
747ffcb611aSDag-Erling Smørgrav 			return (-1);
7487d96f4efSBrian Somers 			break;
7497d96f4efSBrian Somers 		}
7507d96f4efSBrian Somers 
751d9e630b5SAndrey A. Chernov 		do {
752d9e630b5SAndrey A. Chernov 			token = strsep(&res, " \t");
753d9e630b5SAndrey A. Chernov 		} while (token != NULL && !*token);
7547d96f4efSBrian Somers 	}
7557d96f4efSBrian Somers #undef STATE_READ_KEYWORD
7567d96f4efSBrian Somers #undef STATE_READ_TYPE
7577d96f4efSBrian Somers #undef STATE_READ_PORT
7587d96f4efSBrian Somers #undef STATE_READ_SERVER
7597d96f4efSBrian Somers #undef STATE_READ_RULE
7607d96f4efSBrian Somers #undef STATE_READ_DELETE
7617d96f4efSBrian Somers #undef STATE_READ_PROTO
7627d96f4efSBrian Somers #undef STATE_READ_SRC
7637d96f4efSBrian Somers #undef STATE_READ_DST
7647d96f4efSBrian Somers 
7657d96f4efSBrian Somers /* Convert port strings to numbers.  This needs to be done after
7667d96f4efSBrian Somers    the string is parsed, because the prototype might not be designated
7677d96f4efSBrian Somers    before the ports (which might be symbolic entries in /etc/services) */
7687d96f4efSBrian Somers 
769f0f93429SDag-Erling Smørgrav 	if (strlen(str_port) != 0) {
7707d96f4efSBrian Somers 		int err;
7717d96f4efSBrian Somers 
7727d96f4efSBrian Somers 		err = IpPort(str_port, proto, &proxy_port);
7737d96f4efSBrian Somers 		if (err)
774ffcb611aSDag-Erling Smørgrav 			return (-1);
775f0f93429SDag-Erling Smørgrav 	} else {
7767d96f4efSBrian Somers 		proxy_port = 0;
7777d96f4efSBrian Somers 	}
7787d96f4efSBrian Somers 
779f0f93429SDag-Erling Smørgrav 	if (strlen(str_server_port) != 0) {
7807d96f4efSBrian Somers 		int err;
7817d96f4efSBrian Somers 
7827d96f4efSBrian Somers 		err = IpPort(str_server_port, proto, &server_port);
7837d96f4efSBrian Somers 		if (err)
784ffcb611aSDag-Erling Smørgrav 			return (-1);
785f0f93429SDag-Erling Smørgrav 	} else {
7867d96f4efSBrian Somers 		server_port = 0;
7877d96f4efSBrian Somers 	}
7887d96f4efSBrian Somers 
7897d96f4efSBrian Somers /* Check that at least the server address has been defined */
7907d96f4efSBrian Somers 	if (server_addr.s_addr == 0)
791ffcb611aSDag-Erling Smørgrav 		return (-1);
7927d96f4efSBrian Somers 
7937d96f4efSBrian Somers /* Add to linked list */
7947d96f4efSBrian Somers 	proxy_entry = malloc(sizeof(struct proxy_entry));
7957d96f4efSBrian Somers 	if (proxy_entry == NULL)
796ffcb611aSDag-Erling Smørgrav 		return (-1);
7977d96f4efSBrian Somers 
7987d96f4efSBrian Somers 	proxy_entry->proxy_type = proxy_type;
7997d96f4efSBrian Somers 	proxy_entry->rule_index = rule_index;
8007d96f4efSBrian Somers 	proxy_entry->proto = proto;
8017d96f4efSBrian Somers 	proxy_entry->proxy_port = htons(proxy_port);
8027d96f4efSBrian Somers 	proxy_entry->server_port = htons(server_port);
8037d96f4efSBrian Somers 	proxy_entry->server_addr = server_addr;
8047d96f4efSBrian Somers 	proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
8057d96f4efSBrian Somers 	proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
8067d96f4efSBrian Somers 	proxy_entry->src_mask = src_mask;
8077d96f4efSBrian Somers 	proxy_entry->dst_mask = dst_mask;
8087d96f4efSBrian Somers 
8095e289f9eSPoul-Henning Kamp 	RuleAdd(la, proxy_entry);
8107d96f4efSBrian Somers 
811ffcb611aSDag-Erling Smørgrav 	return (0);
8127d96f4efSBrian Somers }
813