1*7d96f4efSBrian Somers /* file: alias_proxy.c 2*7d96f4efSBrian Somers 3*7d96f4efSBrian Somers This file encapsulates special operations related to transparent 4*7d96f4efSBrian Somers proxy redirection. This is where packets with a particular destination, 5*7d96f4efSBrian Somers usually tcp port 80, are redirected to a proxy server. 6*7d96f4efSBrian Somers 7*7d96f4efSBrian Somers When packets are proxied, the destination address and port are 8*7d96f4efSBrian Somers modified. In certain cases, it is necessary to somehow encode 9*7d96f4efSBrian Somers the original address/port info into the packet. Two methods are 10*7d96f4efSBrian Somers presently supported: addition of a [DEST addr port] string at the 11*7d96f4efSBrian Somers beginning a of tcp stream, or inclusion of an optional field 12*7d96f4efSBrian Somers in the IP header. 13*7d96f4efSBrian Somers 14*7d96f4efSBrian Somers There is one public API function: 15*7d96f4efSBrian Somers 16*7d96f4efSBrian Somers PacketAliasProxyRule() -- Adds and deletes proxy 17*7d96f4efSBrian Somers rules. 18*7d96f4efSBrian Somers 19*7d96f4efSBrian Somers Rules are stored in a linear linked list, so lookup efficiency 20*7d96f4efSBrian Somers won't be too good for large lists. 21*7d96f4efSBrian Somers 22*7d96f4efSBrian Somers 23*7d96f4efSBrian Somers Initial development: April, 1998 (cjm) 24*7d96f4efSBrian Somers */ 25*7d96f4efSBrian Somers 26*7d96f4efSBrian Somers 27*7d96f4efSBrian Somers /* System includes */ 28*7d96f4efSBrian Somers #include <ctype.h> 29*7d96f4efSBrian Somers #include <stdio.h> 30*7d96f4efSBrian Somers #include <stdlib.h> 31*7d96f4efSBrian Somers #include <string.h> 32*7d96f4efSBrian Somers #include <netdb.h> 33*7d96f4efSBrian Somers 34*7d96f4efSBrian Somers #include <sys/types.h> 35*7d96f4efSBrian Somers #include <sys/socket.h> 36*7d96f4efSBrian Somers 37*7d96f4efSBrian Somers /* BSD IPV4 includes */ 38*7d96f4efSBrian Somers #include <netinet/in_systm.h> 39*7d96f4efSBrian Somers #include <netinet/in.h> 40*7d96f4efSBrian Somers #include <netinet/ip.h> 41*7d96f4efSBrian Somers #include <netinet/tcp.h> 42*7d96f4efSBrian Somers 43*7d96f4efSBrian Somers #include <arpa/inet.h> 44*7d96f4efSBrian Somers 45*7d96f4efSBrian Somers #include "alias_local.h" /* Functions used by alias*.c */ 46*7d96f4efSBrian Somers #include "alias.h" /* Public API functions for libalias */ 47*7d96f4efSBrian Somers 48*7d96f4efSBrian Somers 49*7d96f4efSBrian Somers 50*7d96f4efSBrian Somers /* 51*7d96f4efSBrian Somers Data structures 52*7d96f4efSBrian Somers */ 53*7d96f4efSBrian Somers 54*7d96f4efSBrian Somers /* 55*7d96f4efSBrian Somers * A linked list of arbitrary length, based on struct proxy_entry is 56*7d96f4efSBrian Somers * used to store proxy rules. 57*7d96f4efSBrian Somers */ 58*7d96f4efSBrian Somers struct proxy_entry 59*7d96f4efSBrian Somers { 60*7d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE 1 61*7d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2 62*7d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR 3 63*7d96f4efSBrian Somers int rule_index; 64*7d96f4efSBrian Somers int proxy_type; 65*7d96f4efSBrian Somers u_char proto; 66*7d96f4efSBrian Somers u_short proxy_port; 67*7d96f4efSBrian Somers u_short server_port; 68*7d96f4efSBrian Somers 69*7d96f4efSBrian Somers struct in_addr server_addr; 70*7d96f4efSBrian Somers 71*7d96f4efSBrian Somers struct in_addr src_addr; 72*7d96f4efSBrian Somers struct in_addr src_mask; 73*7d96f4efSBrian Somers 74*7d96f4efSBrian Somers struct in_addr dst_addr; 75*7d96f4efSBrian Somers struct in_addr dst_mask; 76*7d96f4efSBrian Somers 77*7d96f4efSBrian Somers struct proxy_entry *next; 78*7d96f4efSBrian Somers struct proxy_entry *last; 79*7d96f4efSBrian Somers }; 80*7d96f4efSBrian Somers 81*7d96f4efSBrian Somers 82*7d96f4efSBrian Somers 83*7d96f4efSBrian Somers /* 84*7d96f4efSBrian Somers File scope variables 85*7d96f4efSBrian Somers */ 86*7d96f4efSBrian Somers 87*7d96f4efSBrian Somers static struct proxy_entry *proxyList; 88*7d96f4efSBrian Somers 89*7d96f4efSBrian Somers 90*7d96f4efSBrian Somers 91*7d96f4efSBrian Somers /* Local (static) functions: 92*7d96f4efSBrian Somers 93*7d96f4efSBrian Somers IpMask() -- Utility function for creating IP 94*7d96f4efSBrian Somers masks from integer (1-32) specification. 95*7d96f4efSBrian Somers IpAddr() -- Utility function for converting string 96*7d96f4efSBrian Somers to IP address 97*7d96f4efSBrian Somers IpPort() -- Utility function for converting string 98*7d96f4efSBrian Somers to port number 99*7d96f4efSBrian Somers RuleAdd() -- Adds an element to the rule list. 100*7d96f4efSBrian Somers RuleDelete() -- Removes an element from the rule list. 101*7d96f4efSBrian Somers RuleNumberDelete() -- Removes all elements from the rule list 102*7d96f4efSBrian Somers having a certain rule number. 103*7d96f4efSBrian Somers ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning 104*7d96f4efSBrian Somers of a TCP stream. 105*7d96f4efSBrian Somers ProxyEncodeIpHeader() -- Adds an IP option indicating the true 106*7d96f4efSBrian Somers destination of a proxied IP packet 107*7d96f4efSBrian Somers */ 108*7d96f4efSBrian Somers 109*7d96f4efSBrian Somers static int IpMask(int, struct in_addr *); 110*7d96f4efSBrian Somers static int IpAddr(char *, struct in_addr *); 111*7d96f4efSBrian Somers static int IpPort(char *, int, int *); 112*7d96f4efSBrian Somers static void RuleAdd(struct proxy_entry *); 113*7d96f4efSBrian Somers static void RuleDelete(struct proxy_entry *); 114*7d96f4efSBrian Somers static int RuleNumberDelete(int); 115*7d96f4efSBrian Somers static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 116*7d96f4efSBrian Somers static void ProxyEncodeIpHeader(struct ip *, int); 117*7d96f4efSBrian Somers 118*7d96f4efSBrian Somers static int 119*7d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask) 120*7d96f4efSBrian Somers { 121*7d96f4efSBrian Somers int i; 122*7d96f4efSBrian Somers u_int imask; 123*7d96f4efSBrian Somers 124*7d96f4efSBrian Somers if (nbits < 0 || nbits > 32) 125*7d96f4efSBrian Somers return -1; 126*7d96f4efSBrian Somers 127*7d96f4efSBrian Somers imask = 0; 128*7d96f4efSBrian Somers for (i=0; i<nbits; i++) 129*7d96f4efSBrian Somers imask = (imask >> 1) + 0x80000000; 130*7d96f4efSBrian Somers mask->s_addr = htonl(imask); 131*7d96f4efSBrian Somers 132*7d96f4efSBrian Somers return 0; 133*7d96f4efSBrian Somers } 134*7d96f4efSBrian Somers 135*7d96f4efSBrian Somers static int 136*7d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr) 137*7d96f4efSBrian Somers { 138*7d96f4efSBrian Somers if (inet_aton(s, addr) == 0) 139*7d96f4efSBrian Somers return -1; 140*7d96f4efSBrian Somers else 141*7d96f4efSBrian Somers return 0; 142*7d96f4efSBrian Somers } 143*7d96f4efSBrian Somers 144*7d96f4efSBrian Somers static int 145*7d96f4efSBrian Somers IpPort(char *s, int proto, int *port) 146*7d96f4efSBrian Somers { 147*7d96f4efSBrian Somers int n; 148*7d96f4efSBrian Somers 149*7d96f4efSBrian Somers n = sscanf(s, "%d", port); 150*7d96f4efSBrian Somers if (n != 1) 151*7d96f4efSBrian Somers { 152*7d96f4efSBrian Somers struct servent *se; 153*7d96f4efSBrian Somers 154*7d96f4efSBrian Somers if (proto == IPPROTO_TCP) 155*7d96f4efSBrian Somers se = getservbyname(s, "tcp"); 156*7d96f4efSBrian Somers else if (proto == IPPROTO_UDP) 157*7d96f4efSBrian Somers se = getservbyname(s, "udp"); 158*7d96f4efSBrian Somers else 159*7d96f4efSBrian Somers return -1; 160*7d96f4efSBrian Somers 161*7d96f4efSBrian Somers if (se == NULL) 162*7d96f4efSBrian Somers return -1; 163*7d96f4efSBrian Somers 164*7d96f4efSBrian Somers *port = (u_int) ntohs(se->s_port); 165*7d96f4efSBrian Somers } 166*7d96f4efSBrian Somers 167*7d96f4efSBrian Somers return 0; 168*7d96f4efSBrian Somers } 169*7d96f4efSBrian Somers 170*7d96f4efSBrian Somers void 171*7d96f4efSBrian Somers RuleAdd(struct proxy_entry *entry) 172*7d96f4efSBrian Somers { 173*7d96f4efSBrian Somers int rule_index; 174*7d96f4efSBrian Somers struct proxy_entry *ptr; 175*7d96f4efSBrian Somers struct proxy_entry *ptr_last; 176*7d96f4efSBrian Somers 177*7d96f4efSBrian Somers if (proxyList == NULL) 178*7d96f4efSBrian Somers { 179*7d96f4efSBrian Somers proxyList = entry; 180*7d96f4efSBrian Somers entry->last = NULL; 181*7d96f4efSBrian Somers entry->next = NULL; 182*7d96f4efSBrian Somers return; 183*7d96f4efSBrian Somers } 184*7d96f4efSBrian Somers 185*7d96f4efSBrian Somers rule_index = entry->rule_index; 186*7d96f4efSBrian Somers ptr = proxyList; 187*7d96f4efSBrian Somers ptr_last = NULL; 188*7d96f4efSBrian Somers while (ptr != NULL) 189*7d96f4efSBrian Somers { 190*7d96f4efSBrian Somers if (ptr->rule_index >= rule_index) 191*7d96f4efSBrian Somers { 192*7d96f4efSBrian Somers if (ptr_last == NULL) 193*7d96f4efSBrian Somers { 194*7d96f4efSBrian Somers entry->next = proxyList; 195*7d96f4efSBrian Somers entry->last = NULL; 196*7d96f4efSBrian Somers proxyList->last = entry; 197*7d96f4efSBrian Somers proxyList = entry; 198*7d96f4efSBrian Somers return; 199*7d96f4efSBrian Somers } 200*7d96f4efSBrian Somers 201*7d96f4efSBrian Somers ptr_last->next = entry; 202*7d96f4efSBrian Somers ptr->last = entry; 203*7d96f4efSBrian Somers entry->last = ptr->last; 204*7d96f4efSBrian Somers entry->next = ptr; 205*7d96f4efSBrian Somers return; 206*7d96f4efSBrian Somers } 207*7d96f4efSBrian Somers ptr_last = ptr; 208*7d96f4efSBrian Somers ptr = ptr->next; 209*7d96f4efSBrian Somers } 210*7d96f4efSBrian Somers 211*7d96f4efSBrian Somers ptr_last->next = entry; 212*7d96f4efSBrian Somers entry->last = ptr_last; 213*7d96f4efSBrian Somers entry->next = NULL; 214*7d96f4efSBrian Somers } 215*7d96f4efSBrian Somers 216*7d96f4efSBrian Somers static void 217*7d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry) 218*7d96f4efSBrian Somers { 219*7d96f4efSBrian Somers if (entry->last != NULL) 220*7d96f4efSBrian Somers entry->last->next = entry->next; 221*7d96f4efSBrian Somers else 222*7d96f4efSBrian Somers proxyList = entry->next; 223*7d96f4efSBrian Somers 224*7d96f4efSBrian Somers if (entry->next != NULL) 225*7d96f4efSBrian Somers entry->next->last = entry->last; 226*7d96f4efSBrian Somers 227*7d96f4efSBrian Somers free(entry); 228*7d96f4efSBrian Somers } 229*7d96f4efSBrian Somers 230*7d96f4efSBrian Somers static int 231*7d96f4efSBrian Somers RuleNumberDelete(int rule_index) 232*7d96f4efSBrian Somers { 233*7d96f4efSBrian Somers int err; 234*7d96f4efSBrian Somers struct proxy_entry *ptr; 235*7d96f4efSBrian Somers 236*7d96f4efSBrian Somers err = -1; 237*7d96f4efSBrian Somers ptr = proxyList; 238*7d96f4efSBrian Somers while (ptr != NULL) 239*7d96f4efSBrian Somers { 240*7d96f4efSBrian Somers struct proxy_entry *ptr_next; 241*7d96f4efSBrian Somers 242*7d96f4efSBrian Somers ptr_next = ptr->next; 243*7d96f4efSBrian Somers if (ptr->rule_index == rule_index) 244*7d96f4efSBrian Somers { 245*7d96f4efSBrian Somers err = 0; 246*7d96f4efSBrian Somers RuleDelete(ptr); 247*7d96f4efSBrian Somers } 248*7d96f4efSBrian Somers 249*7d96f4efSBrian Somers ptr = ptr_next; 250*7d96f4efSBrian Somers } 251*7d96f4efSBrian Somers 252*7d96f4efSBrian Somers return err; 253*7d96f4efSBrian Somers } 254*7d96f4efSBrian Somers 255*7d96f4efSBrian Somers static void 256*7d96f4efSBrian Somers ProxyEncodeTcpStream(struct alias_link *link, 257*7d96f4efSBrian Somers struct ip *pip, 258*7d96f4efSBrian Somers int maxpacketsize) 259*7d96f4efSBrian Somers { 260*7d96f4efSBrian Somers int slen; 261*7d96f4efSBrian Somers char buffer[40]; 262*7d96f4efSBrian Somers struct tcphdr *tc; 263*7d96f4efSBrian Somers 264*7d96f4efSBrian Somers /* Compute pointer to tcp header */ 265*7d96f4efSBrian Somers tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 266*7d96f4efSBrian Somers 267*7d96f4efSBrian Somers /* Don't modify if once already modified */ 268*7d96f4efSBrian Somers 269*7d96f4efSBrian Somers if (GetAckModified (link)) 270*7d96f4efSBrian Somers return; 271*7d96f4efSBrian Somers 272*7d96f4efSBrian Somers /* Translate destination address and port to string form */ 273*7d96f4efSBrian Somers snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 274*7d96f4efSBrian Somers inet_ntoa(GetProxyAddress (link)), (u_int) ntohs(GetProxyPort (link))); 275*7d96f4efSBrian Somers 276*7d96f4efSBrian Somers /* Pad string out to a multiple of two in length */ 277*7d96f4efSBrian Somers slen = strlen(buffer); 278*7d96f4efSBrian Somers switch (slen % 2) 279*7d96f4efSBrian Somers { 280*7d96f4efSBrian Somers case 0: 281*7d96f4efSBrian Somers strcat(buffer, " \n"); 282*7d96f4efSBrian Somers slen += 2; 283*7d96f4efSBrian Somers break; 284*7d96f4efSBrian Somers case 1: 285*7d96f4efSBrian Somers strcat(buffer, "\n"); 286*7d96f4efSBrian Somers slen += 1; 287*7d96f4efSBrian Somers } 288*7d96f4efSBrian Somers 289*7d96f4efSBrian Somers /* Check for packet overflow */ 290*7d96f4efSBrian Somers if ((ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 291*7d96f4efSBrian Somers return; 292*7d96f4efSBrian Somers 293*7d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */ 294*7d96f4efSBrian Somers { 295*7d96f4efSBrian Somers int dlen; 296*7d96f4efSBrian Somers int hlen; 297*7d96f4efSBrian Somers u_char *p; 298*7d96f4efSBrian Somers 299*7d96f4efSBrian Somers hlen = (pip->ip_hl + tc->th_off) << 2; 300*7d96f4efSBrian Somers dlen = ntohs (pip->ip_len) - hlen; 301*7d96f4efSBrian Somers 302*7d96f4efSBrian Somers /* Modify first packet that has data in it */ 303*7d96f4efSBrian Somers 304*7d96f4efSBrian Somers if (dlen == 0) 305*7d96f4efSBrian Somers return; 306*7d96f4efSBrian Somers 307*7d96f4efSBrian Somers p = (char *) pip; 308*7d96f4efSBrian Somers p += hlen; 309*7d96f4efSBrian Somers 310*7d96f4efSBrian Somers memmove(p + slen, p, dlen); 311*7d96f4efSBrian Somers memcpy(p, buffer, slen); 312*7d96f4efSBrian Somers } 313*7d96f4efSBrian Somers 314*7d96f4efSBrian Somers /* Save information about modfied sequence number */ 315*7d96f4efSBrian Somers { 316*7d96f4efSBrian Somers int delta; 317*7d96f4efSBrian Somers 318*7d96f4efSBrian Somers SetAckModified(link); 319*7d96f4efSBrian Somers delta = GetDeltaSeqOut(pip, link); 320*7d96f4efSBrian Somers AddSeq(pip, link, delta+slen); 321*7d96f4efSBrian Somers } 322*7d96f4efSBrian Somers 323*7d96f4efSBrian Somers /* Update IP header packet length and checksum */ 324*7d96f4efSBrian Somers { 325*7d96f4efSBrian Somers int accumulate; 326*7d96f4efSBrian Somers 327*7d96f4efSBrian Somers accumulate = pip->ip_len; 328*7d96f4efSBrian Somers pip->ip_len = htons(ntohs(pip->ip_len) + slen); 329*7d96f4efSBrian Somers accumulate -= pip->ip_len; 330*7d96f4efSBrian Somers 331*7d96f4efSBrian Somers ADJUST_CHECKSUM(accumulate, pip->ip_sum); 332*7d96f4efSBrian Somers } 333*7d96f4efSBrian Somers 334*7d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have 335*7d96f4efSBrian Somers already changed. */ 336*7d96f4efSBrian Somers 337*7d96f4efSBrian Somers tc->th_sum = 0; 338*7d96f4efSBrian Somers tc->th_sum = TcpChecksum (pip); 339*7d96f4efSBrian Somers } 340*7d96f4efSBrian Somers 341*7d96f4efSBrian Somers static void 342*7d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip, 343*7d96f4efSBrian Somers int maxpacketsize) 344*7d96f4efSBrian Somers { 345*7d96f4efSBrian Somers #define OPTION_LEN_BYTES 8 346*7d96f4efSBrian Somers #define OPTION_LEN_INT16 4 347*7d96f4efSBrian Somers #define OPTION_LEN_INT32 2 348*7d96f4efSBrian Somers u_char option[OPTION_LEN_BYTES]; 349*7d96f4efSBrian Somers 350*7d96f4efSBrian Somers fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 351*7d96f4efSBrian Somers fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 352*7d96f4efSBrian Somers 353*7d96f4efSBrian Somers /* Check to see that there is room to add an IP option */ 354*7d96f4efSBrian Somers if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 355*7d96f4efSBrian Somers return; 356*7d96f4efSBrian Somers 357*7d96f4efSBrian Somers /* Build option and copy into packet */ 358*7d96f4efSBrian Somers { 359*7d96f4efSBrian Somers u_char *ptr; 360*7d96f4efSBrian Somers struct tcphdr *tc; 361*7d96f4efSBrian Somers 362*7d96f4efSBrian Somers ptr = (u_char *) pip; 363*7d96f4efSBrian Somers ptr += 20; 364*7d96f4efSBrian Somers memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 365*7d96f4efSBrian Somers 366*7d96f4efSBrian Somers option[0] = 0x64; /* class: 3 (reserved), option 4 */ 367*7d96f4efSBrian Somers option[1] = OPTION_LEN_BYTES; 368*7d96f4efSBrian Somers 369*7d96f4efSBrian Somers memcpy(&option[2], (u_char *) &pip->ip_dst, 4); 370*7d96f4efSBrian Somers 371*7d96f4efSBrian Somers tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 372*7d96f4efSBrian Somers memcpy(&option[6], (u_char *) &tc->th_sport, 2); 373*7d96f4efSBrian Somers 374*7d96f4efSBrian Somers memcpy(ptr, option, 8); 375*7d96f4efSBrian Somers } 376*7d96f4efSBrian Somers 377*7d96f4efSBrian Somers /* Update checksum, header length and packet length */ 378*7d96f4efSBrian Somers { 379*7d96f4efSBrian Somers int i; 380*7d96f4efSBrian Somers int accumulate; 381*7d96f4efSBrian Somers u_short *sptr; 382*7d96f4efSBrian Somers 383*7d96f4efSBrian Somers sptr = (u_short *) option; 384*7d96f4efSBrian Somers accumulate = 0; 385*7d96f4efSBrian Somers for (i=0; i<OPTION_LEN_INT16; i++) 386*7d96f4efSBrian Somers accumulate -= *(sptr++); 387*7d96f4efSBrian Somers 388*7d96f4efSBrian Somers sptr = (u_short *) pip; 389*7d96f4efSBrian Somers accumulate += *sptr; 390*7d96f4efSBrian Somers pip->ip_hl += OPTION_LEN_INT32; 391*7d96f4efSBrian Somers accumulate -= *sptr; 392*7d96f4efSBrian Somers 393*7d96f4efSBrian Somers accumulate += pip->ip_len; 394*7d96f4efSBrian Somers pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 395*7d96f4efSBrian Somers accumulate -= pip->ip_len; 396*7d96f4efSBrian Somers 397*7d96f4efSBrian Somers ADJUST_CHECKSUM(accumulate, pip->ip_sum); 398*7d96f4efSBrian Somers } 399*7d96f4efSBrian Somers #undef OPTION_LEN_BYTES 400*7d96f4efSBrian Somers #undef OPTION_LEN_INT16 401*7d96f4efSBrian Somers #undef OPTION_LEN_INT32 402*7d96f4efSBrian Somers fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 403*7d96f4efSBrian Somers fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 404*7d96f4efSBrian Somers } 405*7d96f4efSBrian Somers 406*7d96f4efSBrian Somers 407*7d96f4efSBrian Somers /* Functions by other packet alias source files 408*7d96f4efSBrian Somers 409*7d96f4efSBrian Somers ProxyCheck() -- Checks whether an outgoing packet should 410*7d96f4efSBrian Somers be proxied. 411*7d96f4efSBrian Somers ProxyModify() -- Encodes the original destination address/port 412*7d96f4efSBrian Somers for a packet which is to be redirected to 413*7d96f4efSBrian Somers a proxy server. 414*7d96f4efSBrian Somers */ 415*7d96f4efSBrian Somers 416*7d96f4efSBrian Somers int 417*7d96f4efSBrian Somers ProxyCheck(struct ip *pip, 418*7d96f4efSBrian Somers struct in_addr *proxy_server_addr, 419*7d96f4efSBrian Somers u_short *proxy_server_port) 420*7d96f4efSBrian Somers { 421*7d96f4efSBrian Somers u_short dst_port; 422*7d96f4efSBrian Somers struct in_addr src_addr; 423*7d96f4efSBrian Somers struct in_addr dst_addr; 424*7d96f4efSBrian Somers struct proxy_entry *ptr; 425*7d96f4efSBrian Somers 426*7d96f4efSBrian Somers src_addr = pip->ip_src; 427*7d96f4efSBrian Somers dst_addr = pip->ip_dst; 428*7d96f4efSBrian Somers dst_port = ((struct tcphdr *) ((char *) pip + (pip->ip_hl << 2))) 429*7d96f4efSBrian Somers ->th_dport; 430*7d96f4efSBrian Somers 431*7d96f4efSBrian Somers ptr = proxyList; 432*7d96f4efSBrian Somers while (ptr != NULL) 433*7d96f4efSBrian Somers { 434*7d96f4efSBrian Somers u_short proxy_port; 435*7d96f4efSBrian Somers 436*7d96f4efSBrian Somers proxy_port = ptr->proxy_port; 437*7d96f4efSBrian Somers if ((dst_port == proxy_port || proxy_port == 0) 438*7d96f4efSBrian Somers && pip->ip_p == ptr->proto 439*7d96f4efSBrian Somers && src_addr.s_addr != ptr->server_addr.s_addr) 440*7d96f4efSBrian Somers { 441*7d96f4efSBrian Somers struct in_addr src_addr_masked; 442*7d96f4efSBrian Somers struct in_addr dst_addr_masked; 443*7d96f4efSBrian Somers 444*7d96f4efSBrian Somers src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 445*7d96f4efSBrian Somers dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 446*7d96f4efSBrian Somers 447*7d96f4efSBrian Somers if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 448*7d96f4efSBrian Somers && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) 449*7d96f4efSBrian Somers { 450*7d96f4efSBrian Somers if ((*proxy_server_port = ptr->server_port) == 0) 451*7d96f4efSBrian Somers *proxy_server_port = dst_port; 452*7d96f4efSBrian Somers *proxy_server_addr = ptr->server_addr; 453*7d96f4efSBrian Somers return ptr->proxy_type; 454*7d96f4efSBrian Somers } 455*7d96f4efSBrian Somers } 456*7d96f4efSBrian Somers ptr = ptr->next; 457*7d96f4efSBrian Somers } 458*7d96f4efSBrian Somers 459*7d96f4efSBrian Somers return 0; 460*7d96f4efSBrian Somers } 461*7d96f4efSBrian Somers 462*7d96f4efSBrian Somers void 463*7d96f4efSBrian Somers ProxyModify(struct alias_link *link, 464*7d96f4efSBrian Somers struct ip *pip, 465*7d96f4efSBrian Somers int maxpacketsize, 466*7d96f4efSBrian Somers int proxy_type) 467*7d96f4efSBrian Somers { 468*7d96f4efSBrian Somers switch (proxy_type) 469*7d96f4efSBrian Somers { 470*7d96f4efSBrian Somers case PROXY_TYPE_ENCODE_IPHDR: 471*7d96f4efSBrian Somers ProxyEncodeIpHeader(pip, maxpacketsize); 472*7d96f4efSBrian Somers break; 473*7d96f4efSBrian Somers 474*7d96f4efSBrian Somers case PROXY_TYPE_ENCODE_TCPSTREAM: 475*7d96f4efSBrian Somers ProxyEncodeTcpStream(link, pip, maxpacketsize); 476*7d96f4efSBrian Somers break; 477*7d96f4efSBrian Somers } 478*7d96f4efSBrian Somers } 479*7d96f4efSBrian Somers 480*7d96f4efSBrian Somers 481*7d96f4efSBrian Somers /* 482*7d96f4efSBrian Somers Public API functions 483*7d96f4efSBrian Somers */ 484*7d96f4efSBrian Somers 485*7d96f4efSBrian Somers int 486*7d96f4efSBrian Somers PacketAliasProxyRule(char *cmd) 487*7d96f4efSBrian Somers { 488*7d96f4efSBrian Somers /* 489*7d96f4efSBrian Somers * This function takes command strings of the form: 490*7d96f4efSBrian Somers * 491*7d96f4efSBrian Somers * server <addr>[:<port>] 492*7d96f4efSBrian Somers * [port <port>] 493*7d96f4efSBrian Somers * [rule n] 494*7d96f4efSBrian Somers * [proto tcp|udp] 495*7d96f4efSBrian Somers * [src <addr>[/n]] 496*7d96f4efSBrian Somers * [dst <addr>[/n]] 497*7d96f4efSBrian Somers * [type encode_tcp_stream|encode_ip_hdr|no_encode] 498*7d96f4efSBrian Somers * 499*7d96f4efSBrian Somers * delete <rule number> 500*7d96f4efSBrian Somers * 501*7d96f4efSBrian Somers * Subfields can be in arbitrary order. Port numbers and addresses 502*7d96f4efSBrian Somers * must be in either numeric or symbolic form. An optional rule number 503*7d96f4efSBrian Somers * is used to control the order in which rules are searched. If two 504*7d96f4efSBrian Somers * rules have the same number, then search order cannot be guaranteed, 505*7d96f4efSBrian Somers * and the rules should be disjoint. If no rule number is specified, 506*7d96f4efSBrian Somers * then 0 is used, and group 0 rules are always checked before any 507*7d96f4efSBrian Somers * others. 508*7d96f4efSBrian Somers */ 509*7d96f4efSBrian Somers int i, n, len; 510*7d96f4efSBrian Somers int cmd_len; 511*7d96f4efSBrian Somers int token_count; 512*7d96f4efSBrian Somers int state; 513*7d96f4efSBrian Somers char *token; 514*7d96f4efSBrian Somers char buffer[256]; 515*7d96f4efSBrian Somers char str_port[sizeof(buffer)]; 516*7d96f4efSBrian Somers char str_server_port[sizeof(buffer)]; 517*7d96f4efSBrian Somers 518*7d96f4efSBrian Somers int rule_index; 519*7d96f4efSBrian Somers int proto; 520*7d96f4efSBrian Somers int proxy_type; 521*7d96f4efSBrian Somers int proxy_port; 522*7d96f4efSBrian Somers int server_port; 523*7d96f4efSBrian Somers struct in_addr server_addr; 524*7d96f4efSBrian Somers struct in_addr src_addr, src_mask; 525*7d96f4efSBrian Somers struct in_addr dst_addr, dst_mask; 526*7d96f4efSBrian Somers struct proxy_entry *proxy_entry; 527*7d96f4efSBrian Somers 528*7d96f4efSBrian Somers /* Copy command line into a buffer */ 529*7d96f4efSBrian Somers cmd_len = strlen(cmd); 530*7d96f4efSBrian Somers if (cmd_len > (sizeof(buffer) - 1)) 531*7d96f4efSBrian Somers return -1; 532*7d96f4efSBrian Somers strcpy(buffer, cmd); 533*7d96f4efSBrian Somers 534*7d96f4efSBrian Somers /* Convert to lower case */ 535*7d96f4efSBrian Somers len = strlen(buffer); 536*7d96f4efSBrian Somers for (i=0; i<len; i++) 537*7d96f4efSBrian Somers buffer[i] = tolower(buffer[i]); 538*7d96f4efSBrian Somers 539*7d96f4efSBrian Somers /* Set default proxy type */ 540*7d96f4efSBrian Somers 541*7d96f4efSBrian Somers /* Set up default values */ 542*7d96f4efSBrian Somers rule_index = 0; 543*7d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_NONE; 544*7d96f4efSBrian Somers proto = IPPROTO_TCP; 545*7d96f4efSBrian Somers proxy_port = 0; 546*7d96f4efSBrian Somers server_addr.s_addr = 0; 547*7d96f4efSBrian Somers server_port = 0; 548*7d96f4efSBrian Somers src_addr.s_addr = 0; 549*7d96f4efSBrian Somers IpMask(0, &src_mask); 550*7d96f4efSBrian Somers dst_addr.s_addr = 0; 551*7d96f4efSBrian Somers IpMask(0, &dst_mask); 552*7d96f4efSBrian Somers 553*7d96f4efSBrian Somers str_port[0] = 0; 554*7d96f4efSBrian Somers str_server_port[0] = 0; 555*7d96f4efSBrian Somers 556*7d96f4efSBrian Somers /* Parse command string with state machine */ 557*7d96f4efSBrian Somers #define STATE_READ_KEYWORD 0 558*7d96f4efSBrian Somers #define STATE_READ_TYPE 1 559*7d96f4efSBrian Somers #define STATE_READ_PORT 2 560*7d96f4efSBrian Somers #define STATE_READ_SERVER 3 561*7d96f4efSBrian Somers #define STATE_READ_RULE 4 562*7d96f4efSBrian Somers #define STATE_READ_DELETE 5 563*7d96f4efSBrian Somers #define STATE_READ_PROTO 6 564*7d96f4efSBrian Somers #define STATE_READ_SRC 7 565*7d96f4efSBrian Somers #define STATE_READ_DST 8 566*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 567*7d96f4efSBrian Somers token = strtok(buffer, " \t"); 568*7d96f4efSBrian Somers token_count = 0; 569*7d96f4efSBrian Somers while (token != NULL) 570*7d96f4efSBrian Somers { 571*7d96f4efSBrian Somers token_count++; 572*7d96f4efSBrian Somers switch (state) 573*7d96f4efSBrian Somers { 574*7d96f4efSBrian Somers case STATE_READ_KEYWORD: 575*7d96f4efSBrian Somers if (strcmp(token, "type") == 0) 576*7d96f4efSBrian Somers state = STATE_READ_TYPE; 577*7d96f4efSBrian Somers else if (strcmp(token, "port") == 0) 578*7d96f4efSBrian Somers state = STATE_READ_PORT; 579*7d96f4efSBrian Somers else if (strcmp(token, "server") == 0) 580*7d96f4efSBrian Somers state = STATE_READ_SERVER; 581*7d96f4efSBrian Somers else if (strcmp(token, "rule") == 0) 582*7d96f4efSBrian Somers state = STATE_READ_RULE; 583*7d96f4efSBrian Somers else if (strcmp(token, "delete") == 0) 584*7d96f4efSBrian Somers state = STATE_READ_DELETE; 585*7d96f4efSBrian Somers else if (strcmp(token, "proto") == 0) 586*7d96f4efSBrian Somers state = STATE_READ_PROTO; 587*7d96f4efSBrian Somers else if (strcmp(token, "src") == 0) 588*7d96f4efSBrian Somers state = STATE_READ_SRC; 589*7d96f4efSBrian Somers else if (strcmp(token, "dst") == 0) 590*7d96f4efSBrian Somers state = STATE_READ_DST; 591*7d96f4efSBrian Somers else 592*7d96f4efSBrian Somers return -1; 593*7d96f4efSBrian Somers break; 594*7d96f4efSBrian Somers 595*7d96f4efSBrian Somers case STATE_READ_TYPE: 596*7d96f4efSBrian Somers if (strcmp(token, "encode_ip_hdr") == 0) 597*7d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_IPHDR; 598*7d96f4efSBrian Somers else if (strcmp(token, "encode_tcp_stream") == 0) 599*7d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 600*7d96f4efSBrian Somers else if (strcmp(token, "no_encode") == 0) 601*7d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_NONE; 602*7d96f4efSBrian Somers else 603*7d96f4efSBrian Somers return -1; 604*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 605*7d96f4efSBrian Somers break; 606*7d96f4efSBrian Somers 607*7d96f4efSBrian Somers case STATE_READ_PORT: 608*7d96f4efSBrian Somers strcpy(str_port, token); 609*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 610*7d96f4efSBrian Somers break; 611*7d96f4efSBrian Somers 612*7d96f4efSBrian Somers case STATE_READ_SERVER: 613*7d96f4efSBrian Somers { 614*7d96f4efSBrian Somers int err; 615*7d96f4efSBrian Somers char *p; 616*7d96f4efSBrian Somers char s[sizeof(buffer)]; 617*7d96f4efSBrian Somers 618*7d96f4efSBrian Somers p = token; 619*7d96f4efSBrian Somers while (*p != ':' && *p != 0) 620*7d96f4efSBrian Somers p++; 621*7d96f4efSBrian Somers 622*7d96f4efSBrian Somers if (*p != ':') 623*7d96f4efSBrian Somers { 624*7d96f4efSBrian Somers err = IpAddr(token, &server_addr); 625*7d96f4efSBrian Somers if (err) 626*7d96f4efSBrian Somers return -1; 627*7d96f4efSBrian Somers } 628*7d96f4efSBrian Somers else 629*7d96f4efSBrian Somers { 630*7d96f4efSBrian Somers *p = ' '; 631*7d96f4efSBrian Somers 632*7d96f4efSBrian Somers n = sscanf(token, "%s %s", s, str_server_port); 633*7d96f4efSBrian Somers if (n != 2) 634*7d96f4efSBrian Somers return -1; 635*7d96f4efSBrian Somers 636*7d96f4efSBrian Somers err = IpAddr(s, &server_addr); 637*7d96f4efSBrian Somers if (err) 638*7d96f4efSBrian Somers return -1; 639*7d96f4efSBrian Somers } 640*7d96f4efSBrian Somers } 641*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 642*7d96f4efSBrian Somers break; 643*7d96f4efSBrian Somers 644*7d96f4efSBrian Somers case STATE_READ_RULE: 645*7d96f4efSBrian Somers n = sscanf(token, "%d", &rule_index); 646*7d96f4efSBrian Somers if (n != 1 || rule_index < 0) 647*7d96f4efSBrian Somers return -1; 648*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 649*7d96f4efSBrian Somers break; 650*7d96f4efSBrian Somers 651*7d96f4efSBrian Somers case STATE_READ_DELETE: 652*7d96f4efSBrian Somers { 653*7d96f4efSBrian Somers int err; 654*7d96f4efSBrian Somers int rule_to_delete; 655*7d96f4efSBrian Somers 656*7d96f4efSBrian Somers if (token_count != 2) 657*7d96f4efSBrian Somers return -1; 658*7d96f4efSBrian Somers 659*7d96f4efSBrian Somers n = sscanf(token, "%d", &rule_to_delete); 660*7d96f4efSBrian Somers if (n != 1) 661*7d96f4efSBrian Somers return -1; 662*7d96f4efSBrian Somers err = RuleNumberDelete(rule_to_delete); 663*7d96f4efSBrian Somers if (err) 664*7d96f4efSBrian Somers return -1; 665*7d96f4efSBrian Somers return 0; 666*7d96f4efSBrian Somers } 667*7d96f4efSBrian Somers 668*7d96f4efSBrian Somers case STATE_READ_PROTO: 669*7d96f4efSBrian Somers if (strcmp(token, "tcp") == 0) 670*7d96f4efSBrian Somers proto = IPPROTO_TCP; 671*7d96f4efSBrian Somers else if (strcmp(token, "udp") == 0) 672*7d96f4efSBrian Somers proto = IPPROTO_UDP; 673*7d96f4efSBrian Somers else 674*7d96f4efSBrian Somers return -1; 675*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 676*7d96f4efSBrian Somers break; 677*7d96f4efSBrian Somers 678*7d96f4efSBrian Somers case STATE_READ_SRC: 679*7d96f4efSBrian Somers case STATE_READ_DST: 680*7d96f4efSBrian Somers { 681*7d96f4efSBrian Somers int err; 682*7d96f4efSBrian Somers char *p; 683*7d96f4efSBrian Somers struct in_addr mask; 684*7d96f4efSBrian Somers struct in_addr addr; 685*7d96f4efSBrian Somers 686*7d96f4efSBrian Somers p = token; 687*7d96f4efSBrian Somers while (*p != '/' && *p != 0) 688*7d96f4efSBrian Somers p++; 689*7d96f4efSBrian Somers 690*7d96f4efSBrian Somers if (*p != '/') 691*7d96f4efSBrian Somers { 692*7d96f4efSBrian Somers IpMask(32, &mask); 693*7d96f4efSBrian Somers err = IpAddr(token, &addr); 694*7d96f4efSBrian Somers if (err) 695*7d96f4efSBrian Somers return -1; 696*7d96f4efSBrian Somers } 697*7d96f4efSBrian Somers else 698*7d96f4efSBrian Somers { 699*7d96f4efSBrian Somers int n; 700*7d96f4efSBrian Somers int nbits; 701*7d96f4efSBrian Somers char s[sizeof(buffer)]; 702*7d96f4efSBrian Somers 703*7d96f4efSBrian Somers *p = ' '; 704*7d96f4efSBrian Somers n = sscanf(token, "%s %d", s, &nbits); 705*7d96f4efSBrian Somers if (n != 2) 706*7d96f4efSBrian Somers return -1; 707*7d96f4efSBrian Somers 708*7d96f4efSBrian Somers err = IpAddr(s, &addr); 709*7d96f4efSBrian Somers if (err) 710*7d96f4efSBrian Somers return -1; 711*7d96f4efSBrian Somers 712*7d96f4efSBrian Somers err = IpMask(nbits, &mask); 713*7d96f4efSBrian Somers if (err) 714*7d96f4efSBrian Somers return -1; 715*7d96f4efSBrian Somers } 716*7d96f4efSBrian Somers 717*7d96f4efSBrian Somers if (state == STATE_READ_SRC) 718*7d96f4efSBrian Somers { 719*7d96f4efSBrian Somers src_addr = addr; 720*7d96f4efSBrian Somers src_mask = mask; 721*7d96f4efSBrian Somers } 722*7d96f4efSBrian Somers else 723*7d96f4efSBrian Somers { 724*7d96f4efSBrian Somers dst_addr = addr; 725*7d96f4efSBrian Somers dst_mask = mask; 726*7d96f4efSBrian Somers } 727*7d96f4efSBrian Somers } 728*7d96f4efSBrian Somers state = STATE_READ_KEYWORD; 729*7d96f4efSBrian Somers break; 730*7d96f4efSBrian Somers 731*7d96f4efSBrian Somers default: 732*7d96f4efSBrian Somers return -1; 733*7d96f4efSBrian Somers break; 734*7d96f4efSBrian Somers } 735*7d96f4efSBrian Somers 736*7d96f4efSBrian Somers token = strtok(NULL, " \t"); 737*7d96f4efSBrian Somers } 738*7d96f4efSBrian Somers #undef STATE_READ_KEYWORD 739*7d96f4efSBrian Somers #undef STATE_READ_TYPE 740*7d96f4efSBrian Somers #undef STATE_READ_PORT 741*7d96f4efSBrian Somers #undef STATE_READ_SERVER 742*7d96f4efSBrian Somers #undef STATE_READ_RULE 743*7d96f4efSBrian Somers #undef STATE_READ_DELETE 744*7d96f4efSBrian Somers #undef STATE_READ_PROTO 745*7d96f4efSBrian Somers #undef STATE_READ_SRC 746*7d96f4efSBrian Somers #undef STATE_READ_DST 747*7d96f4efSBrian Somers 748*7d96f4efSBrian Somers /* Convert port strings to numbers. This needs to be done after 749*7d96f4efSBrian Somers the string is parsed, because the prototype might not be designated 750*7d96f4efSBrian Somers before the ports (which might be symbolic entries in /etc/services) */ 751*7d96f4efSBrian Somers 752*7d96f4efSBrian Somers if (strlen(str_port) != 0) 753*7d96f4efSBrian Somers { 754*7d96f4efSBrian Somers int err; 755*7d96f4efSBrian Somers 756*7d96f4efSBrian Somers err = IpPort(str_port, proto, &proxy_port); 757*7d96f4efSBrian Somers if (err) 758*7d96f4efSBrian Somers return -1; 759*7d96f4efSBrian Somers } 760*7d96f4efSBrian Somers else 761*7d96f4efSBrian Somers { 762*7d96f4efSBrian Somers proxy_port = 0; 763*7d96f4efSBrian Somers } 764*7d96f4efSBrian Somers 765*7d96f4efSBrian Somers if (strlen(str_server_port) != 0) 766*7d96f4efSBrian Somers { 767*7d96f4efSBrian Somers int err; 768*7d96f4efSBrian Somers 769*7d96f4efSBrian Somers err = IpPort(str_server_port, proto, &server_port); 770*7d96f4efSBrian Somers if (err) 771*7d96f4efSBrian Somers return -1; 772*7d96f4efSBrian Somers } 773*7d96f4efSBrian Somers else 774*7d96f4efSBrian Somers { 775*7d96f4efSBrian Somers server_port = 0; 776*7d96f4efSBrian Somers } 777*7d96f4efSBrian Somers 778*7d96f4efSBrian Somers /* Check that at least the server address has been defined */ 779*7d96f4efSBrian Somers if (server_addr.s_addr == 0) 780*7d96f4efSBrian Somers return -1; 781*7d96f4efSBrian Somers 782*7d96f4efSBrian Somers /* Add to linked list */ 783*7d96f4efSBrian Somers proxy_entry = malloc(sizeof(struct proxy_entry)); 784*7d96f4efSBrian Somers if (proxy_entry == NULL) 785*7d96f4efSBrian Somers return -1; 786*7d96f4efSBrian Somers 787*7d96f4efSBrian Somers proxy_entry->proxy_type = proxy_type; 788*7d96f4efSBrian Somers proxy_entry->rule_index = rule_index; 789*7d96f4efSBrian Somers proxy_entry->proto = proto; 790*7d96f4efSBrian Somers proxy_entry->proxy_port = htons(proxy_port); 791*7d96f4efSBrian Somers proxy_entry->server_port = htons(server_port); 792*7d96f4efSBrian Somers proxy_entry->server_addr = server_addr; 793*7d96f4efSBrian Somers proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 794*7d96f4efSBrian Somers proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 795*7d96f4efSBrian Somers proxy_entry->src_mask = src_mask; 796*7d96f4efSBrian Somers proxy_entry->dst_mask = dst_mask; 797*7d96f4efSBrian Somers 798*7d96f4efSBrian Somers RuleAdd(proxy_entry); 799*7d96f4efSBrian Somers 800*7d96f4efSBrian Somers return 0; 801*7d96f4efSBrian Somers } 802