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