17d96f4efSBrian Somers /* file: alias_proxy.c
27d96f4efSBrian Somers 
37d96f4efSBrian Somers     This file encapsulates special operations related to transparent
47d96f4efSBrian Somers     proxy redirection.  This is where packets with a particular destination,
57d96f4efSBrian Somers     usually tcp port 80, are redirected to a proxy server.
67d96f4efSBrian Somers 
77d96f4efSBrian Somers     When packets are proxied, the destination address and port are
87d96f4efSBrian Somers     modified.  In certain cases, it is necessary to somehow encode
97d96f4efSBrian Somers     the original address/port info into the packet.  Two methods are
107d96f4efSBrian Somers     presently supported: addition of a [DEST addr port] string at the
117d96f4efSBrian Somers     beginning a of tcp stream, or inclusion of an optional field
127d96f4efSBrian Somers     in the IP header.
137d96f4efSBrian Somers 
147d96f4efSBrian Somers     There is one public API function:
157d96f4efSBrian Somers 
167d96f4efSBrian Somers         PacketAliasProxyRule()    -- Adds and deletes proxy
177d96f4efSBrian Somers                                      rules.
187d96f4efSBrian Somers 
197d96f4efSBrian Somers     Rules are stored in a linear linked list, so lookup efficiency
207d96f4efSBrian Somers     won't be too good for large lists.
217d96f4efSBrian Somers 
227d96f4efSBrian Somers 
237d96f4efSBrian Somers     Initial development: April, 1998 (cjm)
247d96f4efSBrian Somers */
257d96f4efSBrian Somers 
267d96f4efSBrian Somers 
277d96f4efSBrian Somers /* System includes */
287d96f4efSBrian Somers #include <ctype.h>
297d96f4efSBrian Somers #include <stdio.h>
307d96f4efSBrian Somers #include <stdlib.h>
317d96f4efSBrian Somers #include <string.h>
327d96f4efSBrian Somers #include <netdb.h>
337d96f4efSBrian Somers 
347d96f4efSBrian Somers #include <sys/types.h>
357d96f4efSBrian Somers #include <sys/socket.h>
367d96f4efSBrian Somers 
377d96f4efSBrian Somers /* BSD IPV4 includes */
387d96f4efSBrian Somers #include <netinet/in_systm.h>
397d96f4efSBrian Somers #include <netinet/in.h>
407d96f4efSBrian Somers #include <netinet/ip.h>
417d96f4efSBrian Somers #include <netinet/tcp.h>
427d96f4efSBrian Somers 
437d96f4efSBrian Somers #include <arpa/inet.h>
447d96f4efSBrian Somers 
457d96f4efSBrian Somers #include "alias_local.h"  /* Functions used by alias*.c */
467d96f4efSBrian Somers #include "alias.h"        /* Public API functions for libalias */
477d96f4efSBrian Somers 
487d96f4efSBrian Somers 
497d96f4efSBrian Somers 
507d96f4efSBrian Somers /*
517d96f4efSBrian Somers     Data structures
527d96f4efSBrian Somers  */
537d96f4efSBrian Somers 
547d96f4efSBrian Somers /*
557d96f4efSBrian Somers  * A linked list of arbitrary length, based on struct proxy_entry is
567d96f4efSBrian Somers  * used to store proxy rules.
577d96f4efSBrian Somers  */
587d96f4efSBrian Somers struct proxy_entry
597d96f4efSBrian Somers {
607d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE      1
617d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2
627d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR     3
637d96f4efSBrian Somers     int rule_index;
647d96f4efSBrian Somers     int proxy_type;
657d96f4efSBrian Somers     u_char proto;
667d96f4efSBrian Somers     u_short proxy_port;
677d96f4efSBrian Somers     u_short server_port;
687d96f4efSBrian Somers 
697d96f4efSBrian Somers     struct in_addr server_addr;
707d96f4efSBrian Somers 
717d96f4efSBrian Somers     struct in_addr src_addr;
727d96f4efSBrian Somers     struct in_addr src_mask;
737d96f4efSBrian Somers 
747d96f4efSBrian Somers     struct in_addr dst_addr;
757d96f4efSBrian Somers     struct in_addr dst_mask;
767d96f4efSBrian Somers 
777d96f4efSBrian Somers     struct proxy_entry *next;
787d96f4efSBrian Somers     struct proxy_entry *last;
797d96f4efSBrian Somers };
807d96f4efSBrian Somers 
817d96f4efSBrian Somers 
827d96f4efSBrian Somers 
837d96f4efSBrian Somers /*
847d96f4efSBrian Somers     File scope variables
857d96f4efSBrian Somers */
867d96f4efSBrian Somers 
877d96f4efSBrian Somers static struct proxy_entry *proxyList;
887d96f4efSBrian Somers 
897d96f4efSBrian Somers 
907d96f4efSBrian Somers 
917d96f4efSBrian Somers /* Local (static) functions:
927d96f4efSBrian Somers 
937d96f4efSBrian Somers     IpMask()                 -- Utility function for creating IP
947d96f4efSBrian Somers                                 masks from integer (1-32) specification.
957d96f4efSBrian Somers     IpAddr()                 -- Utility function for converting string
967d96f4efSBrian Somers                                 to IP address
977d96f4efSBrian Somers     IpPort()                 -- Utility function for converting string
987d96f4efSBrian Somers                                 to port number
997d96f4efSBrian Somers     RuleAdd()                -- Adds an element to the rule list.
1007d96f4efSBrian Somers     RuleDelete()             -- Removes an element from the rule list.
1017d96f4efSBrian Somers     RuleNumberDelete()       -- Removes all elements from the rule list
1027d96f4efSBrian Somers                                 having a certain rule number.
1037d96f4efSBrian Somers     ProxyEncodeTcpStream()   -- Adds [DEST x.x.x.x xxxx] to the beginning
1047d96f4efSBrian Somers                                 of a TCP stream.
1057d96f4efSBrian Somers     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
1067d96f4efSBrian Somers                                 destination of a proxied IP packet
1077d96f4efSBrian Somers */
1087d96f4efSBrian Somers 
1097d96f4efSBrian Somers static int IpMask(int, struct in_addr *);
1107d96f4efSBrian Somers static int IpAddr(char *, struct in_addr *);
1117d96f4efSBrian Somers static int IpPort(char *, int, int *);
1127d96f4efSBrian Somers static void RuleAdd(struct proxy_entry *);
1137d96f4efSBrian Somers static void RuleDelete(struct proxy_entry *);
1147d96f4efSBrian Somers static int RuleNumberDelete(int);
1157d96f4efSBrian Somers static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
1167d96f4efSBrian Somers static void ProxyEncodeIpHeader(struct ip *, int);
1177d96f4efSBrian Somers 
1187d96f4efSBrian Somers static int
1197d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask)
1207d96f4efSBrian Somers {
1217d96f4efSBrian Somers     int i;
1227d96f4efSBrian Somers     u_int imask;
1237d96f4efSBrian Somers 
1247d96f4efSBrian Somers     if (nbits < 0 || nbits > 32)
1257d96f4efSBrian Somers         return -1;
1267d96f4efSBrian Somers 
1277d96f4efSBrian Somers     imask = 0;
1287d96f4efSBrian Somers     for (i=0; i<nbits; i++)
1297d96f4efSBrian Somers         imask = (imask >> 1) + 0x80000000;
1307d96f4efSBrian Somers     mask->s_addr = htonl(imask);
1317d96f4efSBrian Somers 
1327d96f4efSBrian Somers     return 0;
1337d96f4efSBrian Somers }
1347d96f4efSBrian Somers 
1357d96f4efSBrian Somers static int
1367d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr)
1377d96f4efSBrian Somers {
1387d96f4efSBrian Somers     if (inet_aton(s, addr) == 0)
1397d96f4efSBrian Somers         return -1;
1407d96f4efSBrian Somers     else
1417d96f4efSBrian Somers         return 0;
1427d96f4efSBrian Somers }
1437d96f4efSBrian Somers 
1447d96f4efSBrian Somers static int
1457d96f4efSBrian Somers IpPort(char *s, int proto, int *port)
1467d96f4efSBrian Somers {
1477d96f4efSBrian Somers     int n;
1487d96f4efSBrian Somers 
1497d96f4efSBrian Somers     n = sscanf(s, "%d", port);
1507d96f4efSBrian Somers     if (n != 1)
1517d96f4efSBrian Somers     {
1527d96f4efSBrian Somers         struct servent *se;
1537d96f4efSBrian Somers 
1547d96f4efSBrian Somers         if (proto == IPPROTO_TCP)
1557d96f4efSBrian Somers             se = getservbyname(s, "tcp");
1567d96f4efSBrian Somers         else if (proto == IPPROTO_UDP)
1577d96f4efSBrian Somers             se = getservbyname(s, "udp");
1587d96f4efSBrian Somers         else
1597d96f4efSBrian Somers             return -1;
1607d96f4efSBrian Somers 
1617d96f4efSBrian Somers         if (se == NULL)
1627d96f4efSBrian Somers                 return -1;
1637d96f4efSBrian Somers 
1647d96f4efSBrian Somers         *port = (u_int) ntohs(se->s_port);
1657d96f4efSBrian Somers     }
1667d96f4efSBrian Somers 
1677d96f4efSBrian Somers     return 0;
1687d96f4efSBrian Somers }
1697d96f4efSBrian Somers 
1707d96f4efSBrian Somers void
1717d96f4efSBrian Somers RuleAdd(struct proxy_entry *entry)
1727d96f4efSBrian Somers {
1737d96f4efSBrian Somers     int rule_index;
1747d96f4efSBrian Somers     struct proxy_entry *ptr;
1757d96f4efSBrian Somers     struct proxy_entry *ptr_last;
1767d96f4efSBrian Somers 
1777d96f4efSBrian Somers     if (proxyList == NULL)
1787d96f4efSBrian Somers     {
1797d96f4efSBrian Somers         proxyList = entry;
1807d96f4efSBrian Somers         entry->last = NULL;
1817d96f4efSBrian Somers         entry->next = NULL;
1827d96f4efSBrian Somers         return;
1837d96f4efSBrian Somers     }
1847d96f4efSBrian Somers 
1857d96f4efSBrian Somers     rule_index = entry->rule_index;
1867d96f4efSBrian Somers     ptr = proxyList;
1877d96f4efSBrian Somers     ptr_last = NULL;
1887d96f4efSBrian Somers     while (ptr != NULL)
1897d96f4efSBrian Somers     {
1907d96f4efSBrian Somers         if (ptr->rule_index >= rule_index)
1917d96f4efSBrian Somers         {
1927d96f4efSBrian Somers             if (ptr_last == NULL)
1937d96f4efSBrian Somers             {
1947d96f4efSBrian Somers                 entry->next = proxyList;
1957d96f4efSBrian Somers                 entry->last = NULL;
1967d96f4efSBrian Somers                 proxyList->last = entry;
1977d96f4efSBrian Somers                 proxyList = entry;
1987d96f4efSBrian Somers                 return;
1997d96f4efSBrian Somers             }
2007d96f4efSBrian Somers 
2017d96f4efSBrian Somers             ptr_last->next = entry;
2027d96f4efSBrian Somers             ptr->last = entry;
2037d96f4efSBrian Somers             entry->last = ptr->last;
2047d96f4efSBrian Somers             entry->next = ptr;
2057d96f4efSBrian Somers             return;
2067d96f4efSBrian Somers         }
2077d96f4efSBrian Somers         ptr_last = ptr;
2087d96f4efSBrian Somers         ptr = ptr->next;
2097d96f4efSBrian Somers     }
2107d96f4efSBrian Somers 
2117d96f4efSBrian Somers     ptr_last->next = entry;
2127d96f4efSBrian Somers     entry->last = ptr_last;
2137d96f4efSBrian Somers     entry->next = NULL;
2147d96f4efSBrian Somers }
2157d96f4efSBrian Somers 
2167d96f4efSBrian Somers static void
2177d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry)
2187d96f4efSBrian Somers {
2197d96f4efSBrian Somers     if (entry->last != NULL)
2207d96f4efSBrian Somers         entry->last->next = entry->next;
2217d96f4efSBrian Somers     else
2227d96f4efSBrian Somers         proxyList = entry->next;
2237d96f4efSBrian Somers 
2247d96f4efSBrian Somers     if (entry->next != NULL)
2257d96f4efSBrian Somers         entry->next->last = entry->last;
2267d96f4efSBrian Somers 
2277d96f4efSBrian Somers     free(entry);
2287d96f4efSBrian Somers }
2297d96f4efSBrian Somers 
2307d96f4efSBrian Somers static int
2317d96f4efSBrian Somers RuleNumberDelete(int rule_index)
2327d96f4efSBrian Somers {
2337d96f4efSBrian Somers     int err;
2347d96f4efSBrian Somers     struct proxy_entry *ptr;
2357d96f4efSBrian Somers 
2367d96f4efSBrian Somers     err = -1;
2377d96f4efSBrian Somers     ptr = proxyList;
2387d96f4efSBrian Somers     while (ptr != NULL)
2397d96f4efSBrian Somers     {
2407d96f4efSBrian Somers         struct proxy_entry *ptr_next;
2417d96f4efSBrian Somers 
2427d96f4efSBrian Somers         ptr_next = ptr->next;
2437d96f4efSBrian Somers         if (ptr->rule_index == rule_index)
2447d96f4efSBrian Somers         {
2457d96f4efSBrian Somers             err = 0;
2467d96f4efSBrian Somers             RuleDelete(ptr);
2477d96f4efSBrian Somers         }
2487d96f4efSBrian Somers 
2497d96f4efSBrian Somers         ptr = ptr_next;
2507d96f4efSBrian Somers     }
2517d96f4efSBrian Somers 
2527d96f4efSBrian Somers     return err;
2537d96f4efSBrian Somers }
2547d96f4efSBrian Somers 
2557d96f4efSBrian Somers static void
2567d96f4efSBrian Somers ProxyEncodeTcpStream(struct alias_link *link,
2577d96f4efSBrian Somers                      struct ip *pip,
2587d96f4efSBrian Somers                      int maxpacketsize)
2597d96f4efSBrian Somers {
2607d96f4efSBrian Somers     int slen;
2617d96f4efSBrian Somers     char buffer[40];
2627d96f4efSBrian Somers     struct tcphdr *tc;
2637d96f4efSBrian Somers 
2647d96f4efSBrian Somers /* Compute pointer to tcp header */
2657d96f4efSBrian Somers     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2667d96f4efSBrian Somers 
2677d96f4efSBrian Somers /* Don't modify if once already modified */
2687d96f4efSBrian Somers 
2697d96f4efSBrian Somers     if (GetAckModified (link))
2707d96f4efSBrian Somers 	return;
2717d96f4efSBrian Somers 
2727d96f4efSBrian Somers /* Translate destination address and port to string form */
2737d96f4efSBrian Somers     snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
2747d96f4efSBrian Somers         inet_ntoa(GetProxyAddress (link)), (u_int) ntohs(GetProxyPort (link)));
2757d96f4efSBrian Somers 
2767d96f4efSBrian Somers /* Pad string out to a multiple of two in length */
2777d96f4efSBrian Somers     slen = strlen(buffer);
2787d96f4efSBrian Somers     switch (slen % 2)
2797d96f4efSBrian Somers     {
2807d96f4efSBrian Somers     case 0:
2817d96f4efSBrian Somers         strcat(buffer, " \n");
2827d96f4efSBrian Somers 	slen += 2;
2837d96f4efSBrian Somers         break;
2847d96f4efSBrian Somers     case 1:
2857d96f4efSBrian Somers         strcat(buffer, "\n");
2867d96f4efSBrian Somers 	slen += 1;
2877d96f4efSBrian Somers     }
2887d96f4efSBrian Somers 
2897d96f4efSBrian Somers /* Check for packet overflow */
2907d96f4efSBrian Somers     if ((ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
2917d96f4efSBrian Somers         return;
2927d96f4efSBrian Somers 
2937d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */
2947d96f4efSBrian Somers     {
2957d96f4efSBrian Somers         int dlen;
2967d96f4efSBrian Somers         int hlen;
2977d96f4efSBrian Somers         u_char *p;
2987d96f4efSBrian Somers 
2997d96f4efSBrian Somers         hlen = (pip->ip_hl + tc->th_off) << 2;
3007d96f4efSBrian Somers         dlen = ntohs (pip->ip_len) - hlen;
3017d96f4efSBrian Somers 
3027d96f4efSBrian Somers /* Modify first packet that has data in it */
3037d96f4efSBrian Somers 
3047d96f4efSBrian Somers 	if (dlen == 0)
3057d96f4efSBrian Somers 		return;
3067d96f4efSBrian Somers 
3077d96f4efSBrian Somers         p = (char *) pip;
3087d96f4efSBrian Somers         p += hlen;
3097d96f4efSBrian Somers 
3107d96f4efSBrian Somers         memmove(p + slen, p, dlen);
3117d96f4efSBrian Somers         memcpy(p, buffer, slen);
3127d96f4efSBrian Somers     }
3137d96f4efSBrian Somers 
3147d96f4efSBrian Somers /* Save information about modfied sequence number */
3157d96f4efSBrian Somers     {
3167d96f4efSBrian Somers         int delta;
3177d96f4efSBrian Somers 
3187d96f4efSBrian Somers         SetAckModified(link);
3197d96f4efSBrian Somers         delta = GetDeltaSeqOut(pip, link);
3207d96f4efSBrian Somers         AddSeq(pip, link, delta+slen);
3217d96f4efSBrian Somers     }
3227d96f4efSBrian Somers 
3237d96f4efSBrian Somers /* Update IP header packet length and checksum */
3247d96f4efSBrian Somers     {
3257d96f4efSBrian Somers         int accumulate;
3267d96f4efSBrian Somers 
3277d96f4efSBrian Somers         accumulate  = pip->ip_len;
3287d96f4efSBrian Somers         pip->ip_len = htons(ntohs(pip->ip_len) + slen);
3297d96f4efSBrian Somers         accumulate -= pip->ip_len;
3307d96f4efSBrian Somers 
3317d96f4efSBrian Somers         ADJUST_CHECKSUM(accumulate, pip->ip_sum);
3327d96f4efSBrian Somers     }
3337d96f4efSBrian Somers 
3347d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have
3357d96f4efSBrian Somers    already changed. */
3367d96f4efSBrian Somers 
3377d96f4efSBrian Somers     tc->th_sum = 0;
3387d96f4efSBrian Somers     tc->th_sum = TcpChecksum (pip);
3397d96f4efSBrian Somers }
3407d96f4efSBrian Somers 
3417d96f4efSBrian Somers static void
3427d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip,
3437d96f4efSBrian Somers                     int maxpacketsize)
3447d96f4efSBrian Somers {
3457d96f4efSBrian Somers #define OPTION_LEN_BYTES  8
3467d96f4efSBrian Somers #define OPTION_LEN_INT16  4
3477d96f4efSBrian Somers #define OPTION_LEN_INT32  2
3487d96f4efSBrian Somers     u_char option[OPTION_LEN_BYTES];
3497d96f4efSBrian Somers 
3504c32f5d2SBrian Somers #ifdef DEBUG
3517d96f4efSBrian Somers     fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
3527d96f4efSBrian Somers     fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
3534c32f5d2SBrian Somers #endif
3547d96f4efSBrian Somers 
3557d96f4efSBrian Somers /* Check to see that there is room to add an IP option */
3567d96f4efSBrian Somers     if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
3577d96f4efSBrian Somers         return;
3587d96f4efSBrian Somers 
3597d96f4efSBrian Somers /* Build option and copy into packet */
3607d96f4efSBrian Somers     {
3617d96f4efSBrian Somers         u_char *ptr;
3627d96f4efSBrian Somers         struct tcphdr *tc;
3637d96f4efSBrian Somers 
3647d96f4efSBrian Somers         ptr = (u_char *) pip;
3657d96f4efSBrian Somers         ptr += 20;
3667d96f4efSBrian Somers         memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
3677d96f4efSBrian Somers 
3687d96f4efSBrian Somers         option[0] = 0x64; /* class: 3 (reserved), option 4 */
3697d96f4efSBrian Somers         option[1] = OPTION_LEN_BYTES;
3707d96f4efSBrian Somers 
3717d96f4efSBrian Somers         memcpy(&option[2], (u_char *) &pip->ip_dst, 4);
3727d96f4efSBrian Somers 
3737d96f4efSBrian Somers         tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
3747d96f4efSBrian Somers         memcpy(&option[6], (u_char *) &tc->th_sport, 2);
3757d96f4efSBrian Somers 
3767d96f4efSBrian Somers         memcpy(ptr, option, 8);
3777d96f4efSBrian Somers     }
3787d96f4efSBrian Somers 
3797d96f4efSBrian Somers /* Update checksum, header length and packet length */
3807d96f4efSBrian Somers     {
3817d96f4efSBrian Somers         int i;
3827d96f4efSBrian Somers         int accumulate;
3837d96f4efSBrian Somers         u_short *sptr;
3847d96f4efSBrian Somers 
3857d96f4efSBrian Somers         sptr = (u_short *) option;
3867d96f4efSBrian Somers         accumulate = 0;
3877d96f4efSBrian Somers         for (i=0; i<OPTION_LEN_INT16; i++)
3887d96f4efSBrian Somers             accumulate -= *(sptr++);
3897d96f4efSBrian Somers 
3907d96f4efSBrian Somers         sptr = (u_short *) pip;
3917d96f4efSBrian Somers         accumulate += *sptr;
3927d96f4efSBrian Somers         pip->ip_hl += OPTION_LEN_INT32;
3937d96f4efSBrian Somers         accumulate -= *sptr;
3947d96f4efSBrian Somers 
3957d96f4efSBrian Somers         accumulate += pip->ip_len;
3967d96f4efSBrian Somers         pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
3977d96f4efSBrian Somers         accumulate -= pip->ip_len;
3987d96f4efSBrian Somers 
3997d96f4efSBrian Somers         ADJUST_CHECKSUM(accumulate, pip->ip_sum);
4007d96f4efSBrian Somers     }
4017d96f4efSBrian Somers #undef OPTION_LEN_BYTES
4027d96f4efSBrian Somers #undef OPTION_LEN_INT16
4037d96f4efSBrian Somers #undef OPTION_LEN_INT32
4044c32f5d2SBrian Somers #ifdef DEBUG
4057d96f4efSBrian Somers     fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
4067d96f4efSBrian Somers     fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
4074c32f5d2SBrian Somers #endif
4087d96f4efSBrian Somers }
4097d96f4efSBrian Somers 
4107d96f4efSBrian Somers 
4117d96f4efSBrian Somers /* Functions by other packet alias source files
4127d96f4efSBrian Somers 
4137d96f4efSBrian Somers     ProxyCheck()         -- Checks whether an outgoing packet should
4147d96f4efSBrian Somers                             be proxied.
4157d96f4efSBrian Somers     ProxyModify()        -- Encodes the original destination address/port
4167d96f4efSBrian Somers                             for a packet which is to be redirected to
4177d96f4efSBrian Somers                             a proxy server.
4187d96f4efSBrian Somers */
4197d96f4efSBrian Somers 
4207d96f4efSBrian Somers int
4217d96f4efSBrian Somers ProxyCheck(struct ip *pip,
4227d96f4efSBrian Somers            struct in_addr *proxy_server_addr,
4237d96f4efSBrian Somers            u_short *proxy_server_port)
4247d96f4efSBrian Somers {
4257d96f4efSBrian Somers     u_short dst_port;
4267d96f4efSBrian Somers     struct in_addr src_addr;
4277d96f4efSBrian Somers     struct in_addr dst_addr;
4287d96f4efSBrian Somers     struct proxy_entry *ptr;
4297d96f4efSBrian Somers 
4307d96f4efSBrian Somers     src_addr = pip->ip_src;
4317d96f4efSBrian Somers     dst_addr = pip->ip_dst;
4327d96f4efSBrian Somers     dst_port = ((struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)))
4337d96f4efSBrian Somers         ->th_dport;
4347d96f4efSBrian Somers 
4357d96f4efSBrian Somers     ptr = proxyList;
4367d96f4efSBrian Somers     while (ptr != NULL)
4377d96f4efSBrian Somers     {
4387d96f4efSBrian Somers         u_short proxy_port;
4397d96f4efSBrian Somers 
4407d96f4efSBrian Somers         proxy_port = ptr->proxy_port;
4417d96f4efSBrian Somers         if ((dst_port == proxy_port || proxy_port == 0)
4427d96f4efSBrian Somers          && pip->ip_p == ptr->proto
4437d96f4efSBrian Somers          && src_addr.s_addr != ptr->server_addr.s_addr)
4447d96f4efSBrian Somers         {
4457d96f4efSBrian Somers             struct in_addr src_addr_masked;
4467d96f4efSBrian Somers             struct in_addr dst_addr_masked;
4477d96f4efSBrian Somers 
4487d96f4efSBrian Somers             src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
4497d96f4efSBrian Somers             dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
4507d96f4efSBrian Somers 
4517d96f4efSBrian Somers             if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
4527d96f4efSBrian Somers              && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr))
4537d96f4efSBrian Somers             {
4547d96f4efSBrian Somers                 if ((*proxy_server_port = ptr->server_port) == 0)
4557d96f4efSBrian Somers                     *proxy_server_port = dst_port;
4567d96f4efSBrian Somers                 *proxy_server_addr = ptr->server_addr;
4577d96f4efSBrian Somers                 return ptr->proxy_type;
4587d96f4efSBrian Somers             }
4597d96f4efSBrian Somers         }
4607d96f4efSBrian Somers         ptr = ptr->next;
4617d96f4efSBrian Somers     }
4627d96f4efSBrian Somers 
4637d96f4efSBrian Somers     return 0;
4647d96f4efSBrian Somers }
4657d96f4efSBrian Somers 
4667d96f4efSBrian Somers void
4677d96f4efSBrian Somers ProxyModify(struct alias_link *link,
4687d96f4efSBrian Somers             struct ip *pip,
4697d96f4efSBrian Somers             int maxpacketsize,
4707d96f4efSBrian Somers             int proxy_type)
4717d96f4efSBrian Somers {
4727d96f4efSBrian Somers     switch (proxy_type)
4737d96f4efSBrian Somers     {
4747d96f4efSBrian Somers     case PROXY_TYPE_ENCODE_IPHDR:
4757d96f4efSBrian Somers         ProxyEncodeIpHeader(pip, maxpacketsize);
4767d96f4efSBrian Somers         break;
4777d96f4efSBrian Somers 
4787d96f4efSBrian Somers     case PROXY_TYPE_ENCODE_TCPSTREAM:
4797d96f4efSBrian Somers         ProxyEncodeTcpStream(link, pip, maxpacketsize);
4807d96f4efSBrian Somers         break;
4817d96f4efSBrian Somers     }
4827d96f4efSBrian Somers }
4837d96f4efSBrian Somers 
4847d96f4efSBrian Somers 
4857d96f4efSBrian Somers /*
4867d96f4efSBrian Somers     Public API functions
4877d96f4efSBrian Somers */
4887d96f4efSBrian Somers 
4897d96f4efSBrian Somers int
490*942759e7SBrian Somers PacketAliasProxyRule(const char *cmd)
4917d96f4efSBrian Somers {
4927d96f4efSBrian Somers /*
4937d96f4efSBrian Somers  * This function takes command strings of the form:
4947d96f4efSBrian Somers  *
4957d96f4efSBrian Somers  *   server <addr>[:<port>]
4967d96f4efSBrian Somers  *   [port <port>]
4977d96f4efSBrian Somers  *   [rule n]
4987d96f4efSBrian Somers  *   [proto tcp|udp]
4997d96f4efSBrian Somers  *   [src <addr>[/n]]
5007d96f4efSBrian Somers  *   [dst <addr>[/n]]
5017d96f4efSBrian Somers  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
5027d96f4efSBrian Somers  *
5037d96f4efSBrian Somers  *   delete <rule number>
5047d96f4efSBrian Somers  *
5057d96f4efSBrian Somers  * Subfields can be in arbitrary order.  Port numbers and addresses
5067d96f4efSBrian Somers  * must be in either numeric or symbolic form. An optional rule number
5077d96f4efSBrian Somers  * is used to control the order in which rules are searched.  If two
5087d96f4efSBrian Somers  * rules have the same number, then search order cannot be guaranteed,
5097d96f4efSBrian Somers  * and the rules should be disjoint.  If no rule number is specified,
5107d96f4efSBrian Somers  * then 0 is used, and group 0 rules are always checked before any
5117d96f4efSBrian Somers  * others.
5127d96f4efSBrian Somers  */
5137d96f4efSBrian Somers     int i, n, len;
5147d96f4efSBrian Somers     int cmd_len;
5157d96f4efSBrian Somers     int token_count;
5167d96f4efSBrian Somers     int state;
5177d96f4efSBrian Somers     char *token;
5187d96f4efSBrian Somers     char buffer[256];
5197d96f4efSBrian Somers     char str_port[sizeof(buffer)];
5207d96f4efSBrian Somers     char str_server_port[sizeof(buffer)];
5217d96f4efSBrian Somers 
5227d96f4efSBrian Somers     int rule_index;
5237d96f4efSBrian Somers     int proto;
5247d96f4efSBrian Somers     int proxy_type;
5257d96f4efSBrian Somers     int proxy_port;
5267d96f4efSBrian Somers     int server_port;
5277d96f4efSBrian Somers     struct in_addr server_addr;
5287d96f4efSBrian Somers     struct in_addr src_addr, src_mask;
5297d96f4efSBrian Somers     struct in_addr dst_addr, dst_mask;
5307d96f4efSBrian Somers     struct proxy_entry *proxy_entry;
5317d96f4efSBrian Somers 
5327d96f4efSBrian Somers /* Copy command line into a buffer */
5337d96f4efSBrian Somers     cmd_len = strlen(cmd);
5347d96f4efSBrian Somers     if (cmd_len > (sizeof(buffer) - 1))
5357d96f4efSBrian Somers         return -1;
5367d96f4efSBrian Somers     strcpy(buffer, cmd);
5377d96f4efSBrian Somers 
5387d96f4efSBrian Somers /* Convert to lower case */
5397d96f4efSBrian Somers     len = strlen(buffer);
5407d96f4efSBrian Somers     for (i=0; i<len; i++)
5417d96f4efSBrian Somers         buffer[i] = tolower(buffer[i]);
5427d96f4efSBrian Somers 
5437d96f4efSBrian Somers /* Set default proxy type */
5447d96f4efSBrian Somers 
5457d96f4efSBrian Somers /* Set up default values */
5467d96f4efSBrian Somers     rule_index = 0;
5477d96f4efSBrian Somers     proxy_type = PROXY_TYPE_ENCODE_NONE;
5487d96f4efSBrian Somers     proto = IPPROTO_TCP;
5497d96f4efSBrian Somers     proxy_port = 0;
5507d96f4efSBrian Somers     server_addr.s_addr = 0;
5517d96f4efSBrian Somers     server_port = 0;
5527d96f4efSBrian Somers     src_addr.s_addr = 0;
5537d96f4efSBrian Somers     IpMask(0, &src_mask);
5547d96f4efSBrian Somers     dst_addr.s_addr = 0;
5557d96f4efSBrian Somers     IpMask(0, &dst_mask);
5567d96f4efSBrian Somers 
5577d96f4efSBrian Somers     str_port[0] = 0;
5587d96f4efSBrian Somers     str_server_port[0] = 0;
5597d96f4efSBrian Somers 
5607d96f4efSBrian Somers /* Parse command string with state machine */
5617d96f4efSBrian Somers #define STATE_READ_KEYWORD    0
5627d96f4efSBrian Somers #define STATE_READ_TYPE       1
5637d96f4efSBrian Somers #define STATE_READ_PORT       2
5647d96f4efSBrian Somers #define STATE_READ_SERVER     3
5657d96f4efSBrian Somers #define STATE_READ_RULE       4
5667d96f4efSBrian Somers #define STATE_READ_DELETE     5
5677d96f4efSBrian Somers #define STATE_READ_PROTO      6
5687d96f4efSBrian Somers #define STATE_READ_SRC        7
5697d96f4efSBrian Somers #define STATE_READ_DST        8
5707d96f4efSBrian Somers     state = STATE_READ_KEYWORD;
5717d96f4efSBrian Somers     token = strtok(buffer, " \t");
5727d96f4efSBrian Somers     token_count = 0;
5737d96f4efSBrian Somers     while (token != NULL)
5747d96f4efSBrian Somers     {
5757d96f4efSBrian Somers         token_count++;
5767d96f4efSBrian Somers         switch (state)
5777d96f4efSBrian Somers         {
5787d96f4efSBrian Somers         case STATE_READ_KEYWORD:
5797d96f4efSBrian Somers             if (strcmp(token, "type") == 0)
5807d96f4efSBrian Somers                 state = STATE_READ_TYPE;
5817d96f4efSBrian Somers             else if (strcmp(token, "port") == 0)
5827d96f4efSBrian Somers                 state = STATE_READ_PORT;
5837d96f4efSBrian Somers             else if (strcmp(token, "server") == 0)
5847d96f4efSBrian Somers                 state = STATE_READ_SERVER;
5857d96f4efSBrian Somers             else if (strcmp(token, "rule") == 0)
5867d96f4efSBrian Somers                 state = STATE_READ_RULE;
5877d96f4efSBrian Somers             else if (strcmp(token, "delete") == 0)
5887d96f4efSBrian Somers                 state = STATE_READ_DELETE;
5897d96f4efSBrian Somers             else if (strcmp(token, "proto") == 0)
5907d96f4efSBrian Somers                 state = STATE_READ_PROTO;
5917d96f4efSBrian Somers             else if (strcmp(token, "src") == 0)
5927d96f4efSBrian Somers                 state = STATE_READ_SRC;
5937d96f4efSBrian Somers             else if (strcmp(token, "dst") == 0)
5947d96f4efSBrian Somers                 state = STATE_READ_DST;
5957d96f4efSBrian Somers             else
5967d96f4efSBrian Somers                 return -1;
5977d96f4efSBrian Somers             break;
5987d96f4efSBrian Somers 
5997d96f4efSBrian Somers         case STATE_READ_TYPE:
6007d96f4efSBrian Somers             if (strcmp(token, "encode_ip_hdr") == 0)
6017d96f4efSBrian Somers                 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
6027d96f4efSBrian Somers             else if (strcmp(token, "encode_tcp_stream") == 0)
6037d96f4efSBrian Somers                 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
6047d96f4efSBrian Somers             else if (strcmp(token, "no_encode") == 0)
6057d96f4efSBrian Somers                 proxy_type = PROXY_TYPE_ENCODE_NONE;
6067d96f4efSBrian Somers             else
6077d96f4efSBrian Somers                 return -1;
6087d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6097d96f4efSBrian Somers             break;
6107d96f4efSBrian Somers 
6117d96f4efSBrian Somers         case STATE_READ_PORT:
6127d96f4efSBrian Somers             strcpy(str_port, token);
6137d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6147d96f4efSBrian Somers             break;
6157d96f4efSBrian Somers 
6167d96f4efSBrian Somers         case STATE_READ_SERVER:
6177d96f4efSBrian Somers             {
6187d96f4efSBrian Somers                 int err;
6197d96f4efSBrian Somers                 char *p;
6207d96f4efSBrian Somers                 char s[sizeof(buffer)];
6217d96f4efSBrian Somers 
6227d96f4efSBrian Somers                 p = token;
6237d96f4efSBrian Somers                 while (*p != ':' && *p != 0)
6247d96f4efSBrian Somers                     p++;
6257d96f4efSBrian Somers 
6267d96f4efSBrian Somers                 if (*p != ':')
6277d96f4efSBrian Somers                 {
6287d96f4efSBrian Somers                     err = IpAddr(token, &server_addr);
6297d96f4efSBrian Somers                     if (err)
6307d96f4efSBrian Somers                         return -1;
6317d96f4efSBrian Somers                 }
6327d96f4efSBrian Somers                 else
6337d96f4efSBrian Somers                 {
6347d96f4efSBrian Somers                     *p = ' ';
6357d96f4efSBrian Somers 
6367d96f4efSBrian Somers                     n = sscanf(token, "%s %s", s, str_server_port);
6377d96f4efSBrian Somers                     if (n != 2)
6387d96f4efSBrian Somers                         return -1;
6397d96f4efSBrian Somers 
6407d96f4efSBrian Somers                     err = IpAddr(s, &server_addr);
6417d96f4efSBrian Somers                     if (err)
6427d96f4efSBrian Somers                         return -1;
6437d96f4efSBrian Somers                 }
6447d96f4efSBrian Somers             }
6457d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6467d96f4efSBrian Somers             break;
6477d96f4efSBrian Somers 
6487d96f4efSBrian Somers         case STATE_READ_RULE:
6497d96f4efSBrian Somers             n = sscanf(token, "%d", &rule_index);
6507d96f4efSBrian Somers             if (n != 1 || rule_index < 0)
6517d96f4efSBrian Somers                 return -1;
6527d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6537d96f4efSBrian Somers             break;
6547d96f4efSBrian Somers 
6557d96f4efSBrian Somers         case STATE_READ_DELETE:
6567d96f4efSBrian Somers             {
6577d96f4efSBrian Somers                 int err;
6587d96f4efSBrian Somers                 int rule_to_delete;
6597d96f4efSBrian Somers 
6607d96f4efSBrian Somers                 if (token_count != 2)
6617d96f4efSBrian Somers                     return -1;
6627d96f4efSBrian Somers 
6637d96f4efSBrian Somers                 n = sscanf(token, "%d", &rule_to_delete);
6647d96f4efSBrian Somers                 if (n != 1)
6657d96f4efSBrian Somers                     return -1;
6667d96f4efSBrian Somers                 err = RuleNumberDelete(rule_to_delete);
6677d96f4efSBrian Somers                 if (err)
6687d96f4efSBrian Somers                     return -1;
6697d96f4efSBrian Somers                 return 0;
6707d96f4efSBrian Somers             }
6717d96f4efSBrian Somers 
6727d96f4efSBrian Somers         case STATE_READ_PROTO:
6737d96f4efSBrian Somers             if (strcmp(token, "tcp") == 0)
6747d96f4efSBrian Somers                 proto = IPPROTO_TCP;
6757d96f4efSBrian Somers             else if (strcmp(token, "udp") == 0)
6767d96f4efSBrian Somers                 proto = IPPROTO_UDP;
6777d96f4efSBrian Somers             else
6787d96f4efSBrian Somers                 return -1;
6797d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
6807d96f4efSBrian Somers             break;
6817d96f4efSBrian Somers 
6827d96f4efSBrian Somers         case STATE_READ_SRC:
6837d96f4efSBrian Somers         case STATE_READ_DST:
6847d96f4efSBrian Somers             {
6857d96f4efSBrian Somers                 int err;
6867d96f4efSBrian Somers                 char *p;
6877d96f4efSBrian Somers                 struct in_addr mask;
6887d96f4efSBrian Somers                 struct in_addr addr;
6897d96f4efSBrian Somers 
6907d96f4efSBrian Somers                 p = token;
6917d96f4efSBrian Somers                 while (*p != '/' && *p != 0)
6927d96f4efSBrian Somers                     p++;
6937d96f4efSBrian Somers 
6947d96f4efSBrian Somers                 if (*p != '/')
6957d96f4efSBrian Somers                 {
6967d96f4efSBrian Somers                      IpMask(32, &mask);
6977d96f4efSBrian Somers                      err = IpAddr(token, &addr);
6987d96f4efSBrian Somers                      if (err)
6997d96f4efSBrian Somers                          return -1;
7007d96f4efSBrian Somers                 }
7017d96f4efSBrian Somers                 else
7027d96f4efSBrian Somers                 {
7037d96f4efSBrian Somers                     int n;
7047d96f4efSBrian Somers                     int nbits;
7057d96f4efSBrian Somers                     char s[sizeof(buffer)];
7067d96f4efSBrian Somers 
7077d96f4efSBrian Somers                     *p = ' ';
7087d96f4efSBrian Somers                     n = sscanf(token, "%s %d", s, &nbits);
7097d96f4efSBrian Somers                     if (n != 2)
7107d96f4efSBrian Somers                         return -1;
7117d96f4efSBrian Somers 
7127d96f4efSBrian Somers                     err = IpAddr(s, &addr);
7137d96f4efSBrian Somers                     if (err)
7147d96f4efSBrian Somers                         return -1;
7157d96f4efSBrian Somers 
7167d96f4efSBrian Somers                     err = IpMask(nbits, &mask);
7177d96f4efSBrian Somers                     if (err)
7187d96f4efSBrian Somers                         return -1;
7197d96f4efSBrian Somers                 }
7207d96f4efSBrian Somers 
7217d96f4efSBrian Somers                 if (state == STATE_READ_SRC)
7227d96f4efSBrian Somers                 {
7237d96f4efSBrian Somers                     src_addr = addr;
7247d96f4efSBrian Somers                     src_mask = mask;
7257d96f4efSBrian Somers                 }
7267d96f4efSBrian Somers                 else
7277d96f4efSBrian Somers                 {
7287d96f4efSBrian Somers                     dst_addr = addr;
7297d96f4efSBrian Somers                     dst_mask = mask;
7307d96f4efSBrian Somers                 }
7317d96f4efSBrian Somers             }
7327d96f4efSBrian Somers             state = STATE_READ_KEYWORD;
7337d96f4efSBrian Somers             break;
7347d96f4efSBrian Somers 
7357d96f4efSBrian Somers         default:
7367d96f4efSBrian Somers             return -1;
7377d96f4efSBrian Somers             break;
7387d96f4efSBrian Somers         }
7397d96f4efSBrian Somers 
7407d96f4efSBrian Somers         token = strtok(NULL, " \t");
7417d96f4efSBrian Somers     }
7427d96f4efSBrian Somers #undef STATE_READ_KEYWORD
7437d96f4efSBrian Somers #undef STATE_READ_TYPE
7447d96f4efSBrian Somers #undef STATE_READ_PORT
7457d96f4efSBrian Somers #undef STATE_READ_SERVER
7467d96f4efSBrian Somers #undef STATE_READ_RULE
7477d96f4efSBrian Somers #undef STATE_READ_DELETE
7487d96f4efSBrian Somers #undef STATE_READ_PROTO
7497d96f4efSBrian Somers #undef STATE_READ_SRC
7507d96f4efSBrian Somers #undef STATE_READ_DST
7517d96f4efSBrian Somers 
7527d96f4efSBrian Somers /* Convert port strings to numbers.  This needs to be done after
7537d96f4efSBrian Somers    the string is parsed, because the prototype might not be designated
7547d96f4efSBrian Somers    before the ports (which might be symbolic entries in /etc/services) */
7557d96f4efSBrian Somers 
7567d96f4efSBrian Somers     if (strlen(str_port) != 0)
7577d96f4efSBrian Somers     {
7587d96f4efSBrian Somers         int err;
7597d96f4efSBrian Somers 
7607d96f4efSBrian Somers         err = IpPort(str_port, proto, &proxy_port);
7617d96f4efSBrian Somers         if (err)
7627d96f4efSBrian Somers             return -1;
7637d96f4efSBrian Somers     }
7647d96f4efSBrian Somers     else
7657d96f4efSBrian Somers     {
7667d96f4efSBrian Somers         proxy_port = 0;
7677d96f4efSBrian Somers     }
7687d96f4efSBrian Somers 
7697d96f4efSBrian Somers     if (strlen(str_server_port) != 0)
7707d96f4efSBrian Somers     {
7717d96f4efSBrian Somers         int err;
7727d96f4efSBrian Somers 
7737d96f4efSBrian Somers         err = IpPort(str_server_port, proto, &server_port);
7747d96f4efSBrian Somers         if (err)
7757d96f4efSBrian Somers             return -1;
7767d96f4efSBrian Somers     }
7777d96f4efSBrian Somers     else
7787d96f4efSBrian Somers     {
7797d96f4efSBrian Somers         server_port = 0;
7807d96f4efSBrian Somers     }
7817d96f4efSBrian Somers 
7827d96f4efSBrian Somers /* Check that at least the server address has been defined */
7837d96f4efSBrian Somers     if (server_addr.s_addr == 0)
7847d96f4efSBrian Somers         return -1;
7857d96f4efSBrian Somers 
7867d96f4efSBrian Somers /* Add to linked list */
7877d96f4efSBrian Somers     proxy_entry = malloc(sizeof(struct proxy_entry));
7887d96f4efSBrian Somers     if (proxy_entry == NULL)
7897d96f4efSBrian Somers         return -1;
7907d96f4efSBrian Somers 
7917d96f4efSBrian Somers     proxy_entry->proxy_type = proxy_type;
7927d96f4efSBrian Somers     proxy_entry->rule_index = rule_index;
7937d96f4efSBrian Somers     proxy_entry->proto = proto;
7947d96f4efSBrian Somers     proxy_entry->proxy_port = htons(proxy_port);
7957d96f4efSBrian Somers     proxy_entry->server_port = htons(server_port);
7967d96f4efSBrian Somers     proxy_entry->server_addr = server_addr;
7977d96f4efSBrian Somers     proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
7987d96f4efSBrian Somers     proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
7997d96f4efSBrian Somers     proxy_entry->src_mask = src_mask;
8007d96f4efSBrian Somers     proxy_entry->dst_mask = dst_mask;
8017d96f4efSBrian Somers 
8027d96f4efSBrian Somers     RuleAdd(proxy_entry);
8037d96f4efSBrian Somers 
8047d96f4efSBrian Somers     return 0;
8057d96f4efSBrian Somers }
806