xref: /freebsd/sys/netinet/libalias/alias_proxy.c (revision 5e289f9eb682d86a53ecf2c20be45175a6491803)
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  */
877d96f4efSBrian Somers struct proxy_entry
887d96f4efSBrian Somers {
895e289f9eSPoul-Henning Kamp     struct libalias *la;
907d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
917d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
927d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
937d96f4efSBrian Somers     int rule_index;
947d96f4efSBrian Somers     int proxy_type;
957d96f4efSBrian Somers     u_char proto;
967d96f4efSBrian Somers     u_short proxy_port;
977d96f4efSBrian Somers     u_short server_port;
987d96f4efSBrian Somers 
997d96f4efSBrian Somers     struct in_addr server_addr;
1007d96f4efSBrian Somers 
1017d96f4efSBrian Somers     struct in_addr src_addr;
1027d96f4efSBrian Somers     struct in_addr src_mask;
1037d96f4efSBrian Somers 
1047d96f4efSBrian Somers     struct in_addr dst_addr;
1057d96f4efSBrian Somers     struct in_addr dst_mask;
1067d96f4efSBrian Somers 
1077d96f4efSBrian Somers     struct proxy_entry *next;
1087d96f4efSBrian Somers     struct proxy_entry *last;
1097d96f4efSBrian Somers };
1107d96f4efSBrian Somers 
1117d96f4efSBrian Somers 
1127d96f4efSBrian Somers 
1137d96f4efSBrian Somers /*
1147d96f4efSBrian Somers     File scope variables
1157d96f4efSBrian Somers */
1167d96f4efSBrian Somers 
1177d96f4efSBrian Somers 
1187d96f4efSBrian Somers 
1197d96f4efSBrian Somers /* Local (static) functions:
1207d96f4efSBrian Somers 
1217d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
1227d96f4efSBrian Somers                                 masks from integer (1-32) specification.
1237d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
1247d96f4efSBrian Somers                                 to IP address
1257d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
1267d96f4efSBrian Somers                                 to port number
1277d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1287d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1297d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1307d96f4efSBrian Somers                                 having a certain rule number.
1317d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1327d96f4efSBrian Somers                                 of a TCP stream.
1337d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1347d96f4efSBrian Somers                                 destination of a proxied IP packet
1357d96f4efSBrian Somers */
1367d96f4efSBrian Somers 
1377d96f4efSBrian Somers static int IpMask(int, struct in_addr *);
1387d96f4efSBrian Somers static int IpAddr(char *, struct in_addr *);
1397d96f4efSBrian Somers static int IpPort(char *, int, int *);
1405e289f9eSPoul-Henning Kamp static void RuleAdd(struct libalias *la, struct proxy_entry *);
1417d96f4efSBrian Somers static void RuleDelete(struct proxy_entry *);
1425e289f9eSPoul-Henning Kamp static int RuleNumberDelete(struct libalias *la, int);
1437d96f4efSBrian Somers static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1447d96f4efSBrian Somers static void ProxyEncodeIpHeader(struct ip *, int);
1457d96f4efSBrian Somers 
1467d96f4efSBrian Somers static int
1477d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
1487d96f4efSBrian Somers {
1497d96f4efSBrian Somers     int i;
1507d96f4efSBrian Somers     u_int imask;
1517d96f4efSBrian Somers 
1527d96f4efSBrian Somers     if (nbits < 0 || nbits > 32)
1537d96f4efSBrian Somers         return -1;
1547d96f4efSBrian Somers 
1557d96f4efSBrian Somers     imask = 0;
1567d96f4efSBrian Somers     for (i=0; i<nbits; i++)
1577d96f4efSBrian Somers         imask = (imask >> 1) + 0x80000000;
1587d96f4efSBrian Somers     mask->s_addr = htonl(imask);
1597d96f4efSBrian Somers 
1607d96f4efSBrian Somers     return 0;
1617d96f4efSBrian Somers }
1627d96f4efSBrian Somers 
1637d96f4efSBrian Somers static int
1647d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
1657d96f4efSBrian Somers {
1667d96f4efSBrian Somers     if (inet_aton(s, addr) == 0)
1677d96f4efSBrian Somers         return -1;
1687d96f4efSBrian Somers     else
1697d96f4efSBrian Somers         return 0;
1707d96f4efSBrian Somers }
1717d96f4efSBrian Somers 
1727d96f4efSBrian Somers static int
1737d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
1747d96f4efSBrian Somers {
1757d96f4efSBrian Somers     int n;
1767d96f4efSBrian Somers 
1777d96f4efSBrian Somers     n = sscanf(s, "%d", port);
1787d96f4efSBrian Somers     if (n != 1)
1797d96f4efSBrian Somers     {
1807d96f4efSBrian Somers         struct servent *se;
1817d96f4efSBrian Somers 
1827d96f4efSBrian Somers         if (proto == IPPROTO_TCP)
1837d96f4efSBrian Somers             se = getservbyname(s, "tcp");
1847d96f4efSBrian Somers         else if (proto == IPPROTO_UDP)
1857d96f4efSBrian Somers             se = getservbyname(s, "udp");
1867d96f4efSBrian Somers         else
1877d96f4efSBrian Somers             return -1;
1887d96f4efSBrian Somers 
1897d96f4efSBrian Somers         if (se == NULL)
1907d96f4efSBrian Somers                 return -1;
1917d96f4efSBrian Somers 
1927d96f4efSBrian Somers         *port = (u_int) ntohs(se->s_port);
1937d96f4efSBrian Somers     }
1947d96f4efSBrian Somers 
1957d96f4efSBrian Somers     return 0;
1967d96f4efSBrian Somers }
1977d96f4efSBrian Somers 
1987d96f4efSBrian Somers void
1995e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry)
2007d96f4efSBrian Somers {
2017d96f4efSBrian Somers     int rule_index;
2027d96f4efSBrian Somers     struct proxy_entry *ptr;
2037d96f4efSBrian Somers     struct proxy_entry *ptr_last;
2047d96f4efSBrian Somers 
2055e289f9eSPoul-Henning Kamp     if (la->proxyList == NULL)
2067d96f4efSBrian Somers     {
2075e289f9eSPoul-Henning Kamp         la->proxyList = entry;
2087d96f4efSBrian Somers         entry->last = NULL;
2097d96f4efSBrian Somers         entry->next = NULL;
2107d96f4efSBrian Somers         return;
2117d96f4efSBrian Somers     }
2125e289f9eSPoul-Henning Kamp     entry->la = la;
2137d96f4efSBrian Somers 
2147d96f4efSBrian Somers     rule_index = entry->rule_index;
2155e289f9eSPoul-Henning Kamp     ptr = la->proxyList;
2167d96f4efSBrian Somers     ptr_last = NULL;
2177d96f4efSBrian Somers     while (ptr != NULL)
2187d96f4efSBrian Somers     {
2197d96f4efSBrian Somers         if (ptr->rule_index >= rule_index)
2207d96f4efSBrian Somers         {
2217d96f4efSBrian Somers             if (ptr_last == NULL)
2227d96f4efSBrian Somers             {
2235e289f9eSPoul-Henning Kamp                 entry->next = la->proxyList;
2247d96f4efSBrian Somers                 entry->last = NULL;
2255e289f9eSPoul-Henning Kamp                 la->proxyList->last = entry;
2265e289f9eSPoul-Henning Kamp                 la->proxyList = entry;
2277d96f4efSBrian Somers                 return;
2287d96f4efSBrian Somers             }
2297d96f4efSBrian Somers 
2307d96f4efSBrian Somers             ptr_last->next = entry;
2317d96f4efSBrian Somers             ptr->last = entry;
2327d96f4efSBrian Somers             entry->last = ptr->last;
2337d96f4efSBrian Somers             entry->next = ptr;
2347d96f4efSBrian Somers             return;
2357d96f4efSBrian Somers         }
2367d96f4efSBrian Somers         ptr_last = ptr;
2377d96f4efSBrian Somers         ptr = ptr->next;
2387d96f4efSBrian Somers     }
2397d96f4efSBrian Somers 
2407d96f4efSBrian Somers     ptr_last->next = entry;
2417d96f4efSBrian Somers     entry->last = ptr_last;
2427d96f4efSBrian Somers     entry->next = NULL;
2437d96f4efSBrian Somers }
2447d96f4efSBrian Somers 
2457d96f4efSBrian Somers static void
2467d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
2477d96f4efSBrian Somers {
2485e289f9eSPoul-Henning Kamp     struct libalias *la;
2495e289f9eSPoul-Henning Kamp 
2505e289f9eSPoul-Henning Kamp     la = entry->la;
2517d96f4efSBrian Somers     if (entry->last != NULL)
2527d96f4efSBrian Somers         entry->last->next = entry->next;
2537d96f4efSBrian Somers     else
2545e289f9eSPoul-Henning Kamp         la->proxyList = entry->next;
2557d96f4efSBrian Somers 
2567d96f4efSBrian Somers     if (entry->next != NULL)
2577d96f4efSBrian Somers         entry->next->last = entry->last;
2587d96f4efSBrian Somers 
2597d96f4efSBrian Somers     free(entry);
2607d96f4efSBrian Somers }
2617d96f4efSBrian Somers 
2627d96f4efSBrian Somers static int
2635e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index)
2647d96f4efSBrian Somers {
2657d96f4efSBrian Somers     int err;
2667d96f4efSBrian Somers     struct proxy_entry *ptr;
2677d96f4efSBrian Somers 
2687d96f4efSBrian Somers     err = -1;
2695e289f9eSPoul-Henning Kamp     ptr = la->proxyList;
2707d96f4efSBrian Somers     while (ptr != NULL)
2717d96f4efSBrian Somers     {
2727d96f4efSBrian Somers         struct proxy_entry *ptr_next;
2737d96f4efSBrian Somers 
2747d96f4efSBrian Somers         ptr_next = ptr->next;
2757d96f4efSBrian Somers         if (ptr->rule_index == rule_index)
2767d96f4efSBrian Somers         {
2777d96f4efSBrian Somers             err = 0;
2787d96f4efSBrian Somers             RuleDelete(ptr);
2797d96f4efSBrian Somers         }
2807d96f4efSBrian Somers 
2817d96f4efSBrian Somers         ptr = ptr_next;
2827d96f4efSBrian Somers     }
2837d96f4efSBrian Somers 
2847d96f4efSBrian Somers     return err;
2857d96f4efSBrian Somers }
2867d96f4efSBrian Somers 
2877d96f4efSBrian Somers static void
2887d96f4efSBrian Somers ProxyEncodeTcpStream(struct alias_link *link,
2897d96f4efSBrian Somers                      struct ip *pip,
2907d96f4efSBrian Somers                      int maxpacketsize)
2917d96f4efSBrian Somers {
2927d96f4efSBrian Somers     int slen;
2937d96f4efSBrian Somers     char buffer[40];
2947d96f4efSBrian Somers     struct tcphdr *tc;
2957d96f4efSBrian Somers 
2967d96f4efSBrian Somers /* Compute pointer to tcp header */
2977d96f4efSBrian Somers     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2987d96f4efSBrian Somers 
2997d96f4efSBrian Somers /* Don't modify if once already modified */
3007d96f4efSBrian Somers 
3017d96f4efSBrian Somers     if (GetAckModified (link))
3027d96f4efSBrian Somers 	return;
3037d96f4efSBrian Somers 
3047d96f4efSBrian Somers /* Translate destination address and port to string form */
3057d96f4efSBrian Somers     snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
3067d96f4efSBrian Somers         inet_ntoa(GetProxyAddress (link)), (u_int) ntohs(GetProxyPort (link)));
3077d96f4efSBrian Somers 
3087d96f4efSBrian Somers /* Pad string out to a multiple of two in length */
3097d96f4efSBrian Somers     slen = strlen(buffer);
3107d96f4efSBrian Somers     switch (slen % 2)
3117d96f4efSBrian Somers     {
3127d96f4efSBrian Somers     case 0:
3137d96f4efSBrian Somers         strcat(buffer, " \n");
3147d96f4efSBrian Somers 	slen += 2;
3157d96f4efSBrian Somers         break;
3167d96f4efSBrian Somers     case 1:
3177d96f4efSBrian Somers         strcat(buffer, "\n");
3187d96f4efSBrian Somers 	slen += 1;
3197d96f4efSBrian Somers     }
3207d96f4efSBrian Somers 
3217d96f4efSBrian Somers /* Check for packet overflow */
3227d96f4efSBrian Somers     if ((ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
3237d96f4efSBrian Somers         return;
3247d96f4efSBrian Somers 
3257d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */
3267d96f4efSBrian Somers     {
3277d96f4efSBrian Somers         int dlen;
3287d96f4efSBrian Somers         int hlen;
3297d96f4efSBrian Somers         u_char *p;
3307d96f4efSBrian Somers 
3317d96f4efSBrian Somers         hlen = (pip->ip_hl + tc->th_off) << 2;
3327d96f4efSBrian Somers         dlen = ntohs (pip->ip_len) - hlen;
3337d96f4efSBrian Somers 
3347d96f4efSBrian Somers /* Modify first packet that has data in it */
3357d96f4efSBrian Somers 
3367d96f4efSBrian Somers 	if (dlen == 0)
3377d96f4efSBrian Somers 		return;
3387d96f4efSBrian Somers 
3397d96f4efSBrian Somers         p = (char *) pip;
3407d96f4efSBrian Somers         p += hlen;
3417d96f4efSBrian Somers 
3427d96f4efSBrian Somers         memmove(p + slen, p, dlen);
3437d96f4efSBrian Somers         memcpy(p, buffer, slen);
3447d96f4efSBrian Somers     }
3457d96f4efSBrian Somers 
3467d96f4efSBrian Somers /* Save information about modfied sequence number */
3477d96f4efSBrian Somers     {
3487d96f4efSBrian Somers         int delta;
3497d96f4efSBrian Somers 
3507d96f4efSBrian Somers         SetAckModified(link);
3517d96f4efSBrian Somers         delta = GetDeltaSeqOut(pip, link);
3527d96f4efSBrian Somers         AddSeq(pip, link, delta+slen);
3537d96f4efSBrian Somers     }
3547d96f4efSBrian Somers 
3557d96f4efSBrian Somers /* Update IP header packet length and checksum */
3567d96f4efSBrian Somers     {
3577d96f4efSBrian Somers         int accumulate;
3587d96f4efSBrian Somers 
3597d96f4efSBrian Somers         accumulate  = pip->ip_len;
3607d96f4efSBrian Somers         pip->ip_len = htons(ntohs(pip->ip_len) + slen);
3617d96f4efSBrian Somers         accumulate -= pip->ip_len;
3627d96f4efSBrian Somers 
3637d96f4efSBrian Somers         ADJUST_CHECKSUM(accumulate, pip->ip_sum);
3647d96f4efSBrian Somers     }
3657d96f4efSBrian Somers 
3667d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have
3677d96f4efSBrian Somers    already changed. */
3687d96f4efSBrian Somers 
3697d96f4efSBrian Somers     tc->th_sum = 0;
3707d96f4efSBrian Somers     tc->th_sum = TcpChecksum (pip);
3717d96f4efSBrian Somers }
3727d96f4efSBrian Somers 
3737d96f4efSBrian Somers static void
3747d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip,
3757d96f4efSBrian Somers                     int maxpacketsize)
3767d96f4efSBrian Somers {
3777d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
3787d96f4efSBrian Somers #define OPTION_LEN_INT16  4
3797d96f4efSBrian Somers #define OPTION_LEN_INT32  2
3807d96f4efSBrian Somers     u_char option[OPTION_LEN_BYTES];
3817d96f4efSBrian Somers 
3824c32f5d2SBrian Somers #ifdef DEBUG
3837d96f4efSBrian Somers     fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
3847d96f4efSBrian Somers     fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
3854c32f5d2SBrian Somers #endif
3867d96f4efSBrian Somers 
3877d96f4efSBrian Somers /* Check to see that there is room to add an IP option */
3887d96f4efSBrian Somers     if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
3897d96f4efSBrian Somers         return;
3907d96f4efSBrian Somers 
3917d96f4efSBrian Somers /* Build option and copy into packet */
3927d96f4efSBrian Somers     {
3937d96f4efSBrian Somers         u_char *ptr;
3947d96f4efSBrian Somers         struct tcphdr *tc;
3957d96f4efSBrian Somers 
3967d96f4efSBrian Somers         ptr = (u_char *) pip;
3977d96f4efSBrian Somers         ptr += 20;
3987d96f4efSBrian Somers         memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
3997d96f4efSBrian Somers 
4007d96f4efSBrian Somers         option[0] = 0x64; /* class: 3 (reserved), option 4 */
4017d96f4efSBrian Somers         option[1] = OPTION_LEN_BYTES;
4027d96f4efSBrian Somers 
4037d96f4efSBrian Somers         memcpy(&option[2], (u_char *) &pip->ip_dst, 4);
4047d96f4efSBrian Somers 
4057d96f4efSBrian Somers         tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
4067d96f4efSBrian Somers         memcpy(&option[6], (u_char *) &tc->th_sport, 2);
4077d96f4efSBrian Somers 
4087d96f4efSBrian Somers         memcpy(ptr, option, 8);
4097d96f4efSBrian Somers     }
4107d96f4efSBrian Somers 
4117d96f4efSBrian Somers /* Update checksum, header length and packet length */
4127d96f4efSBrian Somers     {
4137d96f4efSBrian Somers         int i;
4147d96f4efSBrian Somers         int accumulate;
4157d96f4efSBrian Somers         u_short *sptr;
4167d96f4efSBrian Somers 
4177d96f4efSBrian Somers         sptr = (u_short *) option;
4187d96f4efSBrian Somers         accumulate = 0;
4197d96f4efSBrian Somers         for (i=0; i<OPTION_LEN_INT16; i++)
4207d96f4efSBrian Somers             accumulate -= *(sptr++);
4217d96f4efSBrian Somers 
4227d96f4efSBrian Somers         sptr = (u_short *) pip;
4237d96f4efSBrian Somers         accumulate += *sptr;
4247d96f4efSBrian Somers         pip->ip_hl += OPTION_LEN_INT32;
4257d96f4efSBrian Somers         accumulate -= *sptr;
4267d96f4efSBrian Somers 
4277d96f4efSBrian Somers         accumulate += pip->ip_len;
4287d96f4efSBrian Somers         pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
4297d96f4efSBrian Somers         accumulate -= pip->ip_len;
4307d96f4efSBrian Somers 
4317d96f4efSBrian Somers         ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4327d96f4efSBrian Somers     }
4337d96f4efSBrian Somers #undef OPTION_LEN_BYTES
4347d96f4efSBrian Somers #undef OPTION_LEN_INT16
4357d96f4efSBrian Somers #undef OPTION_LEN_INT32
4364c32f5d2SBrian Somers #ifdef DEBUG
4377d96f4efSBrian Somers     fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
4387d96f4efSBrian Somers     fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
4394c32f5d2SBrian Somers #endif
4407d96f4efSBrian Somers }
4417d96f4efSBrian Somers 
4427d96f4efSBrian Somers 
4437d96f4efSBrian Somers /* Functions by other packet alias source files
4447d96f4efSBrian Somers 
4457d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
4467d96f4efSBrian Somers                             be proxied.
4477d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
4487d96f4efSBrian Somers                             for a packet which is to be redirected to
4497d96f4efSBrian Somers                             a proxy server.
4507d96f4efSBrian Somers */
4517d96f4efSBrian Somers 
4527d96f4efSBrian Somers int
4535e289f9eSPoul-Henning Kamp ProxyCheck(struct libalias *la, struct ip *pip,
4547d96f4efSBrian Somers            struct in_addr *proxy_server_addr,
4557d96f4efSBrian Somers            u_short *proxy_server_port)
4567d96f4efSBrian Somers {
4577d96f4efSBrian Somers     u_short dst_port;
4587d96f4efSBrian Somers     struct in_addr src_addr;
4597d96f4efSBrian Somers     struct in_addr dst_addr;
4607d96f4efSBrian Somers     struct proxy_entry *ptr;
4617d96f4efSBrian Somers 
4627d96f4efSBrian Somers     src_addr = pip->ip_src;
4637d96f4efSBrian Somers     dst_addr = pip->ip_dst;
4647d96f4efSBrian Somers     dst_port = ((struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)))
4657d96f4efSBrian Somers         ->th_dport;
4667d96f4efSBrian Somers 
4675e289f9eSPoul-Henning Kamp     ptr = la->proxyList;
4687d96f4efSBrian Somers     while (ptr != NULL)
4697d96f4efSBrian Somers     {
4707d96f4efSBrian Somers         u_short proxy_port;
4717d96f4efSBrian Somers 
4727d96f4efSBrian Somers         proxy_port = ptr->proxy_port;
4737d96f4efSBrian Somers         if ((dst_port == proxy_port || proxy_port == 0)
4747d96f4efSBrian Somers          && pip->ip_p == ptr->proto
4757d96f4efSBrian Somers          && src_addr.s_addr != ptr->server_addr.s_addr)
4767d96f4efSBrian Somers         {
4777d96f4efSBrian Somers             struct in_addr src_addr_masked;
4787d96f4efSBrian Somers             struct in_addr dst_addr_masked;
4797d96f4efSBrian Somers 
4807d96f4efSBrian Somers             src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
4817d96f4efSBrian Somers             dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
4827d96f4efSBrian Somers 
4837d96f4efSBrian Somers             if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
4847d96f4efSBrian Somers              && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr))
4857d96f4efSBrian Somers             {
4867d96f4efSBrian Somers                 if ((*proxy_server_port = ptr->server_port) == 0)
4877d96f4efSBrian Somers                     *proxy_server_port = dst_port;
4887d96f4efSBrian Somers                 *proxy_server_addr = ptr->server_addr;
4897d96f4efSBrian Somers                 return ptr->proxy_type;
4907d96f4efSBrian Somers             }
4917d96f4efSBrian Somers         }
4927d96f4efSBrian Somers         ptr = ptr->next;
4937d96f4efSBrian Somers     }
4947d96f4efSBrian Somers 
4957d96f4efSBrian Somers     return 0;
4967d96f4efSBrian Somers }
4977d96f4efSBrian Somers 
4987d96f4efSBrian Somers void
4995e289f9eSPoul-Henning Kamp ProxyModify(struct libalias *la, struct alias_link *link,
5007d96f4efSBrian Somers             struct ip *pip,
5017d96f4efSBrian Somers             int maxpacketsize,
5027d96f4efSBrian Somers             int proxy_type)
5037d96f4efSBrian Somers {
5047d96f4efSBrian Somers     switch (proxy_type)
5057d96f4efSBrian Somers     {
5067d96f4efSBrian Somers     case PROXY_TYPE_ENCODE_IPHDR:
5077d96f4efSBrian Somers         ProxyEncodeIpHeader(pip, maxpacketsize);
5087d96f4efSBrian Somers         break;
5097d96f4efSBrian Somers 
5107d96f4efSBrian Somers     case PROXY_TYPE_ENCODE_TCPSTREAM:
5117d96f4efSBrian Somers         ProxyEncodeTcpStream(link, pip, maxpacketsize);
5127d96f4efSBrian Somers         break;
5137d96f4efSBrian Somers     }
5147d96f4efSBrian Somers }
5157d96f4efSBrian Somers 
5167d96f4efSBrian Somers 
5177d96f4efSBrian Somers /*
5187d96f4efSBrian Somers     Public API functions
5197d96f4efSBrian Somers */
5207d96f4efSBrian Somers 
5217d96f4efSBrian Somers int
5225e289f9eSPoul-Henning Kamp LibAliasProxyRule(struct libalias *la, const char *cmd)
5237d96f4efSBrian Somers {
5247d96f4efSBrian Somers /*
5257d96f4efSBrian Somers  * This function takes command strings of the form:
5267d96f4efSBrian Somers  *
5277d96f4efSBrian Somers  *   server <addr>[:<port>]
5287d96f4efSBrian Somers  *   [port <port>]
5297d96f4efSBrian Somers  *   [rule n]
5307d96f4efSBrian Somers  *   [proto tcp|udp]
5317d96f4efSBrian Somers  *   [src <addr>[/n]]
5327d96f4efSBrian Somers  *   [dst <addr>[/n]]
5337d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
5347d96f4efSBrian Somers  *
5357d96f4efSBrian Somers  *   delete <rule number>
5367d96f4efSBrian Somers  *
5377d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
5387d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
5397d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
5407d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
5417d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
5427d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
5437d96f4efSBrian Somers  * others.
5447d96f4efSBrian Somers  */
5457d96f4efSBrian Somers     int i, n, len;
5467d96f4efSBrian Somers     int cmd_len;
5477d96f4efSBrian Somers     int token_count;
5487d96f4efSBrian Somers     int state;
5497d96f4efSBrian Somers     char *token;
5507d96f4efSBrian Somers     char buffer[256];
5517d96f4efSBrian Somers     char str_port[sizeof(buffer)];
5527d96f4efSBrian Somers     char str_server_port[sizeof(buffer)];
553d9e630b5SAndrey A. Chernov     char *res = buffer;
5547d96f4efSBrian Somers 
5557d96f4efSBrian Somers     int rule_index;
5567d96f4efSBrian Somers     int proto;
5577d96f4efSBrian Somers     int proxy_type;
5587d96f4efSBrian Somers     int proxy_port;
5597d96f4efSBrian Somers     int server_port;
5607d96f4efSBrian Somers     struct in_addr server_addr;
5617d96f4efSBrian Somers     struct in_addr src_addr, src_mask;
5627d96f4efSBrian Somers     struct in_addr dst_addr, dst_mask;
5637d96f4efSBrian Somers     struct proxy_entry *proxy_entry;
5647d96f4efSBrian Somers 
5657d96f4efSBrian Somers /* Copy command line into a buffer */
5664834b77dSBrian Somers     cmd += strspn(cmd, " \t");
5677d96f4efSBrian Somers     cmd_len = strlen(cmd);
5687d96f4efSBrian Somers     if (cmd_len > (sizeof(buffer) - 1))
5697d96f4efSBrian Somers         return -1;
5707d96f4efSBrian Somers     strcpy(buffer, cmd);
5717d96f4efSBrian Somers 
5727d96f4efSBrian Somers /* Convert to lower case */
5737d96f4efSBrian Somers     len = strlen(buffer);
5747d96f4efSBrian Somers     for (i=0; i<len; i++)
575d9e630b5SAndrey A. Chernov 	buffer[i] = tolower((unsigned char)buffer[i]);
5767d96f4efSBrian Somers 
5777d96f4efSBrian Somers /* Set default proxy type */
5787d96f4efSBrian Somers 
5797d96f4efSBrian Somers /* Set up default values */
5807d96f4efSBrian Somers     rule_index = 0;
5817d96f4efSBrian Somers     proxy_type = PROXY_TYPE_ENCODE_NONE;
5827d96f4efSBrian Somers     proto = IPPROTO_TCP;
5837d96f4efSBrian Somers     proxy_port = 0;
5847d96f4efSBrian Somers     server_addr.s_addr = 0;
5857d96f4efSBrian Somers     server_port = 0;
5867d96f4efSBrian Somers     src_addr.s_addr = 0;
5877d96f4efSBrian Somers     IpMask(0, &src_mask);
5887d96f4efSBrian Somers     dst_addr.s_addr = 0;
5897d96f4efSBrian Somers     IpMask(0, &dst_mask);
5907d96f4efSBrian Somers 
5917d96f4efSBrian Somers     str_port[0] = 0;
5927d96f4efSBrian Somers     str_server_port[0] = 0;
5937d96f4efSBrian Somers 
5947d96f4efSBrian Somers /* Parse command string with state machine */
5957d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
5967d96f4efSBrian Somers #define STATE_READ_TYPE       1
5977d96f4efSBrian Somers #define STATE_READ_PORT       2
5987d96f4efSBrian Somers #define STATE_READ_SERVER     3
5997d96f4efSBrian Somers #define STATE_READ_RULE       4
6007d96f4efSBrian Somers #define STATE_READ_DELETE     5
6017d96f4efSBrian Somers #define STATE_READ_PROTO      6
6027d96f4efSBrian Somers #define STATE_READ_SRC        7
6037d96f4efSBrian Somers #define STATE_READ_DST        8
6047d96f4efSBrian Somers     state = STATE_READ_KEYWORD;
605d9e630b5SAndrey A. Chernov     token = strsep(&res, " \t");
6067d96f4efSBrian Somers     token_count = 0;
6077d96f4efSBrian Somers     while (token != NULL)
6087d96f4efSBrian Somers     {
6097d96f4efSBrian Somers         token_count++;
6107d96f4efSBrian Somers         switch (state)
6117d96f4efSBrian Somers         {
6127d96f4efSBrian Somers         case STATE_READ_KEYWORD:
6137d96f4efSBrian Somers             if (strcmp(token, "type") == 0)
6147d96f4efSBrian Somers                 state = STATE_READ_TYPE;
6157d96f4efSBrian Somers             else if (strcmp(token, "port") == 0)
6167d96f4efSBrian Somers                 state = STATE_READ_PORT;
6177d96f4efSBrian Somers             else if (strcmp(token, "server") == 0)
6187d96f4efSBrian Somers                 state = STATE_READ_SERVER;
6197d96f4efSBrian Somers             else if (strcmp(token, "rule") == 0)
6207d96f4efSBrian Somers                 state = STATE_READ_RULE;
6217d96f4efSBrian Somers             else if (strcmp(token, "delete") == 0)
6227d96f4efSBrian Somers                 state = STATE_READ_DELETE;
6237d96f4efSBrian Somers             else if (strcmp(token, "proto") == 0)
6247d96f4efSBrian Somers                 state = STATE_READ_PROTO;
6257d96f4efSBrian Somers             else if (strcmp(token, "src") == 0)
6267d96f4efSBrian Somers                 state = STATE_READ_SRC;
6277d96f4efSBrian Somers             else if (strcmp(token, "dst") == 0)
6287d96f4efSBrian Somers                 state = STATE_READ_DST;
6297d96f4efSBrian Somers             else
6307d96f4efSBrian Somers                 return -1;
6317d96f4efSBrian Somers             break;
6327d96f4efSBrian Somers 
6337d96f4efSBrian Somers         case STATE_READ_TYPE:
6347d96f4efSBrian Somers             if (strcmp(token, "encode_ip_hdr") == 0)
6357d96f4efSBrian Somers                 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
6367d96f4efSBrian Somers             else if (strcmp(token, "encode_tcp_stream") == 0)
6377d96f4efSBrian Somers                 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
6387d96f4efSBrian Somers             else if (strcmp(token, "no_encode") == 0)
6397d96f4efSBrian Somers                 proxy_type = PROXY_TYPE_ENCODE_NONE;
6407d96f4efSBrian Somers             else
6417d96f4efSBrian Somers                 return -1;
6427d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6437d96f4efSBrian Somers             break;
6447d96f4efSBrian Somers 
6457d96f4efSBrian Somers         case STATE_READ_PORT:
6467d96f4efSBrian Somers             strcpy(str_port, token);
6477d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6487d96f4efSBrian Somers             break;
6497d96f4efSBrian Somers 
6507d96f4efSBrian Somers         case STATE_READ_SERVER:
6517d96f4efSBrian Somers             {
6527d96f4efSBrian Somers                 int err;
6537d96f4efSBrian Somers                 char *p;
6547d96f4efSBrian Somers                 char s[sizeof(buffer)];
6557d96f4efSBrian Somers 
6567d96f4efSBrian Somers                 p = token;
6577d96f4efSBrian Somers                 while (*p != ':' && *p != 0)
6587d96f4efSBrian Somers                     p++;
6597d96f4efSBrian Somers 
6607d96f4efSBrian Somers                 if (*p != ':')
6617d96f4efSBrian Somers                 {
6627d96f4efSBrian Somers                     err = IpAddr(token, &server_addr);
6637d96f4efSBrian Somers                     if (err)
6647d96f4efSBrian Somers                         return -1;
6657d96f4efSBrian Somers                 }
6667d96f4efSBrian Somers                 else
6677d96f4efSBrian Somers                 {
6687d96f4efSBrian Somers                     *p = ' ';
6697d96f4efSBrian Somers 
6707d96f4efSBrian Somers                     n = sscanf(token, "%s %s", s, str_server_port);
6717d96f4efSBrian Somers                     if (n != 2)
6727d96f4efSBrian Somers                         return -1;
6737d96f4efSBrian Somers 
6747d96f4efSBrian Somers                     err = IpAddr(s, &server_addr);
6757d96f4efSBrian Somers                     if (err)
6767d96f4efSBrian Somers                         return -1;
6777d96f4efSBrian Somers                 }
6787d96f4efSBrian Somers             }
6797d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6807d96f4efSBrian Somers             break;
6817d96f4efSBrian Somers 
6827d96f4efSBrian Somers         case STATE_READ_RULE:
6837d96f4efSBrian Somers             n = sscanf(token, "%d", &rule_index);
6847d96f4efSBrian Somers             if (n != 1 || rule_index < 0)
6857d96f4efSBrian Somers                 return -1;
6867d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6877d96f4efSBrian Somers             break;
6887d96f4efSBrian Somers 
6897d96f4efSBrian Somers         case STATE_READ_DELETE:
6907d96f4efSBrian Somers             {
6917d96f4efSBrian Somers                 int err;
6927d96f4efSBrian Somers                 int rule_to_delete;
6937d96f4efSBrian Somers 
6947d96f4efSBrian Somers                 if (token_count != 2)
6957d96f4efSBrian Somers                     return -1;
6967d96f4efSBrian Somers 
6977d96f4efSBrian Somers                 n = sscanf(token, "%d", &rule_to_delete);
6987d96f4efSBrian Somers                 if (n != 1)
6997d96f4efSBrian Somers                     return -1;
7005e289f9eSPoul-Henning Kamp                 err = RuleNumberDelete(la, rule_to_delete);
7017d96f4efSBrian Somers                 if (err)
7027d96f4efSBrian Somers                     return -1;
7037d96f4efSBrian Somers                 return 0;
7047d96f4efSBrian Somers             }
7057d96f4efSBrian Somers 
7067d96f4efSBrian Somers         case STATE_READ_PROTO:
7077d96f4efSBrian Somers             if (strcmp(token, "tcp") == 0)
7087d96f4efSBrian Somers                 proto = IPPROTO_TCP;
7097d96f4efSBrian Somers             else if (strcmp(token, "udp") == 0)
7107d96f4efSBrian Somers                 proto = IPPROTO_UDP;
7117d96f4efSBrian Somers             else
7127d96f4efSBrian Somers                 return -1;
7137d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
7147d96f4efSBrian Somers             break;
7157d96f4efSBrian Somers 
7167d96f4efSBrian Somers         case STATE_READ_SRC:
7177d96f4efSBrian Somers         case STATE_READ_DST:
7187d96f4efSBrian Somers             {
7197d96f4efSBrian Somers                 int err;
7207d96f4efSBrian Somers                 char *p;
7217d96f4efSBrian Somers                 struct in_addr mask;
7227d96f4efSBrian Somers                 struct in_addr addr;
7237d96f4efSBrian Somers 
7247d96f4efSBrian Somers                 p = token;
7257d96f4efSBrian Somers                 while (*p != '/' && *p != 0)
7267d96f4efSBrian Somers                     p++;
7277d96f4efSBrian Somers 
7287d96f4efSBrian Somers                 if (*p != '/')
7297d96f4efSBrian Somers                 {
7307d96f4efSBrian Somers                      IpMask(32, &mask);
7317d96f4efSBrian Somers                      err = IpAddr(token, &addr);
7327d96f4efSBrian Somers                      if (err)
7337d96f4efSBrian Somers                          return -1;
7347d96f4efSBrian Somers                 }
7357d96f4efSBrian Somers                 else
7367d96f4efSBrian Somers                 {
7377d96f4efSBrian Somers                     int nbits;
7387d96f4efSBrian Somers                     char s[sizeof(buffer)];
7397d96f4efSBrian Somers 
7407d96f4efSBrian Somers                     *p = ' ';
7417d96f4efSBrian Somers                     n = sscanf(token, "%s %d", s, &nbits);
7427d96f4efSBrian Somers                     if (n != 2)
7437d96f4efSBrian Somers                         return -1;
7447d96f4efSBrian Somers 
7457d96f4efSBrian Somers                     err = IpAddr(s, &addr);
7467d96f4efSBrian Somers                     if (err)
7477d96f4efSBrian Somers                         return -1;
7487d96f4efSBrian Somers 
7497d96f4efSBrian Somers                     err = IpMask(nbits, &mask);
7507d96f4efSBrian Somers                     if (err)
7517d96f4efSBrian Somers                         return -1;
7527d96f4efSBrian Somers                 }
7537d96f4efSBrian Somers 
7547d96f4efSBrian Somers                 if (state == STATE_READ_SRC)
7557d96f4efSBrian Somers                 {
7567d96f4efSBrian Somers                     src_addr = addr;
7577d96f4efSBrian Somers                     src_mask = mask;
7587d96f4efSBrian Somers                 }
7597d96f4efSBrian Somers                 else
7607d96f4efSBrian Somers                 {
7617d96f4efSBrian Somers                     dst_addr = addr;
7627d96f4efSBrian Somers                     dst_mask = mask;
7637d96f4efSBrian Somers                 }
7647d96f4efSBrian Somers             }
7657d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
7667d96f4efSBrian Somers             break;
7677d96f4efSBrian Somers 
7687d96f4efSBrian Somers         default:
7697d96f4efSBrian Somers             return -1;
7707d96f4efSBrian Somers             break;
7717d96f4efSBrian Somers         }
7727d96f4efSBrian Somers 
773d9e630b5SAndrey A. Chernov 	do {
774d9e630b5SAndrey A. Chernov 		token = strsep(&res, " \t");
775d9e630b5SAndrey A. Chernov 	} while (token != NULL && !*token);
7767d96f4efSBrian Somers     }
7777d96f4efSBrian Somers #undef STATE_READ_KEYWORD
7787d96f4efSBrian Somers #undef STATE_READ_TYPE
7797d96f4efSBrian Somers #undef STATE_READ_PORT
7807d96f4efSBrian Somers #undef STATE_READ_SERVER
7817d96f4efSBrian Somers #undef STATE_READ_RULE
7827d96f4efSBrian Somers #undef STATE_READ_DELETE
7837d96f4efSBrian Somers #undef STATE_READ_PROTO
7847d96f4efSBrian Somers #undef STATE_READ_SRC
7857d96f4efSBrian Somers #undef STATE_READ_DST
7867d96f4efSBrian Somers 
7877d96f4efSBrian Somers /* Convert port strings to numbers.  This needs to be done after
7887d96f4efSBrian Somers    the string is parsed, because the prototype might not be designated
7897d96f4efSBrian Somers    before the ports (which might be symbolic entries in /etc/services) */
7907d96f4efSBrian Somers 
7917d96f4efSBrian Somers     if (strlen(str_port) != 0)
7927d96f4efSBrian Somers     {
7937d96f4efSBrian Somers         int err;
7947d96f4efSBrian Somers 
7957d96f4efSBrian Somers         err = IpPort(str_port, proto, &proxy_port);
7967d96f4efSBrian Somers         if (err)
7977d96f4efSBrian Somers             return -1;
7987d96f4efSBrian Somers     }
7997d96f4efSBrian Somers     else
8007d96f4efSBrian Somers     {
8017d96f4efSBrian Somers         proxy_port = 0;
8027d96f4efSBrian Somers     }
8037d96f4efSBrian Somers 
8047d96f4efSBrian Somers     if (strlen(str_server_port) != 0)
8057d96f4efSBrian Somers     {
8067d96f4efSBrian Somers         int err;
8077d96f4efSBrian Somers 
8087d96f4efSBrian Somers         err = IpPort(str_server_port, proto, &server_port);
8097d96f4efSBrian Somers         if (err)
8107d96f4efSBrian Somers             return -1;
8117d96f4efSBrian Somers     }
8127d96f4efSBrian Somers     else
8137d96f4efSBrian Somers     {
8147d96f4efSBrian Somers         server_port = 0;
8157d96f4efSBrian Somers     }
8167d96f4efSBrian Somers 
8177d96f4efSBrian Somers /* Check that at least the server address has been defined */
8187d96f4efSBrian Somers     if (server_addr.s_addr == 0)
8197d96f4efSBrian Somers         return -1;
8207d96f4efSBrian Somers 
8217d96f4efSBrian Somers /* Add to linked list */
8227d96f4efSBrian Somers     proxy_entry = malloc(sizeof(struct proxy_entry));
8237d96f4efSBrian Somers     if (proxy_entry == NULL)
8247d96f4efSBrian Somers         return -1;
8257d96f4efSBrian Somers 
8267d96f4efSBrian Somers     proxy_entry->proxy_type = proxy_type;
8277d96f4efSBrian Somers     proxy_entry->rule_index = rule_index;
8287d96f4efSBrian Somers     proxy_entry->proto = proto;
8297d96f4efSBrian Somers     proxy_entry->proxy_port = htons(proxy_port);
8307d96f4efSBrian Somers     proxy_entry->server_port = htons(server_port);
8317d96f4efSBrian Somers     proxy_entry->server_addr = server_addr;
8327d96f4efSBrian Somers     proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
8337d96f4efSBrian Somers     proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
8347d96f4efSBrian Somers     proxy_entry->src_mask = src_mask;
8357d96f4efSBrian Somers     proxy_entry->dst_mask = dst_mask;
8367d96f4efSBrian Somers 
8375e289f9eSPoul-Henning Kamp     RuleAdd(la, proxy_entry);
8387d96f4efSBrian Somers 
8397d96f4efSBrian Somers     return 0;
8407d96f4efSBrian Somers }
841