2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 /* file: alias_proxy.c
32 This file encapsulates special operations related to transparent
33 proxy redirection. This is where packets with a particular destination,
34 usually tcp port 80, are redirected to a proxy server.
36 When packets are proxied, the destination address and port are
37 modified. In certain cases, it is necessary to somehow encode
38 the original address/port info into the packet. Two methods are
39 presently supported: addition of a [DEST addr port] string at the
40 beginning of a tcp stream, or inclusion of an optional field
43 There is one public API function:
45 PacketAliasProxyRule() -- Adds and deletes proxy
48 Rules are stored in a linear linked list, so lookup efficiency
49 won't be too good for large lists.
52 Initial development: April, 1998 (cjm)
58 #include <sys/param.h>
59 #include <sys/ctype.h>
60 #include <sys/libkern.h>
61 #include <sys/kernel.h>
62 #include <sys/malloc.h>
63 #include <sys/limits.h>
65 #include <sys/types.h>
66 #include <sys/socket.h>
72 #include <arpa/inet.h>
75 /* BSD IPV4 includes */
76 #include <netinet/in_systm.h>
77 #include <netinet/in.h>
78 #include <netinet/ip.h>
79 #include <netinet/tcp.h>
82 #include <netinet/libalias/alias.h>
83 #include <netinet/libalias/alias_local.h>
85 #include "alias.h" /* Public API functions for libalias */
86 #include "alias_local.h" /* Functions used by alias*.c */
94 * A linked list of arbitrary length, based on struct proxy_entry is
95 * used to store proxy rules.
99 #define PROXY_TYPE_ENCODE_NONE 1
100 #define PROXY_TYPE_ENCODE_TCPSTREAM 2
101 #define PROXY_TYPE_ENCODE_IPHDR 3
108 struct in_addr server_addr;
110 struct in_addr src_addr;
111 struct in_addr src_mask;
113 struct in_addr dst_addr;
114 struct in_addr dst_mask;
116 struct proxy_entry *next;
117 struct proxy_entry *last;
128 /* Local (static) functions:
130 IpMask() -- Utility function for creating IP
131 masks from integer (1-32) specification.
132 IpAddr() -- Utility function for converting string
134 IpPort() -- Utility function for converting string
136 RuleAdd() -- Adds an element to the rule list.
137 RuleDelete() -- Removes an element from the rule list.
138 RuleNumberDelete() -- Removes all elements from the rule list
139 having a certain rule number.
140 ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning
142 ProxyEncodeIpHeader() -- Adds an IP option indicating the true
143 destination of a proxied IP packet
146 #ifdef _KERNEL /* XXX: can it be moved to libkern? */
147 static int inet_aton(const char *cp, struct in_addr *addr);
149 static int IpMask(int, struct in_addr *);
150 static int IpAddr(char *, struct in_addr *);
151 static int IpPort(char *, int, int *);
152 static void RuleAdd(struct libalias *la, struct proxy_entry *);
153 static void RuleDelete(struct proxy_entry *);
154 static int RuleNumberDelete(struct libalias *la, int);
155 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
156 static void ProxyEncodeIpHeader(struct ip *, int);
162 struct in_addr *addr;
170 c = (const char *)cp;
173 * Run through the string, grabbing numbers until
174 * the end of the string, or some error
180 l = strtoul(c, &endptr, 0);
182 if (l == ULONG_MAX || l == 0)
187 * If the whole string is invalid, endptr will equal
188 * c.. this way we can make sure someone hasn't
189 * gone '.12' or something which would get past
197 /* Check the next character past the previous number's end */
200 /* Make sure we only do 3 dots .. */
201 if (n == 3) /* Whoops. Quit. */
212 if (isspace((unsigned char)*c)) {
216 return (0); /* Invalid character, so fail */
222 * Concoct the address according to
223 * the number of parts specified.
227 case 0: /* a -- 32 bits */
229 * Nothing is necessary here. Overflow checking was
230 * already done in strtoul().
233 case 1: /* a.b -- 8.24 bits */
234 if (val > 0xffffff || parts[0] > 0xff)
236 val |= parts[0] << 24;
239 case 2: /* a.b.c -- 8.8.16 bits */
240 if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
242 val |= (parts[0] << 24) | (parts[1] << 16);
245 case 3: /* a.b.c.d -- 8.8.8.8 bits */
246 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
249 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
254 addr->s_addr = htonl(val);
260 IpMask(int nbits, struct in_addr *mask)
265 if (nbits < 0 || nbits > 32)
269 for (i = 0; i < nbits; i++)
270 imask = (imask >> 1) + 0x80000000;
271 mask->s_addr = htonl(imask);
277 IpAddr(char *s, struct in_addr *addr)
279 if (inet_aton(s, addr) == 0)
286 IpPort(char *s, int proto, int *port)
290 n = sscanf(s, "%d", port);
292 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */
296 if (proto == IPPROTO_TCP)
297 se = getservbyname(s, "tcp");
298 else if (proto == IPPROTO_UDP)
299 se = getservbyname(s, "udp");
306 *port = (u_int) ntohs(se->s_port);
315 RuleAdd(struct libalias *la, struct proxy_entry *entry)
318 struct proxy_entry *ptr;
319 struct proxy_entry *ptr_last;
321 if (la->proxyList == NULL) {
322 la->proxyList = entry;
329 rule_index = entry->rule_index;
332 while (ptr != NULL) {
333 if (ptr->rule_index >= rule_index) {
334 if (ptr_last == NULL) {
335 entry->next = la->proxyList;
337 la->proxyList->last = entry;
338 la->proxyList = entry;
341 ptr_last->next = entry;
343 entry->last = ptr->last;
351 ptr_last->next = entry;
352 entry->last = ptr_last;
357 RuleDelete(struct proxy_entry *entry)
362 if (entry->last != NULL)
363 entry->last->next = entry->next;
365 la->proxyList = entry->next;
367 if (entry->next != NULL)
368 entry->next->last = entry->last;
374 RuleNumberDelete(struct libalias *la, int rule_index)
377 struct proxy_entry *ptr;
381 while (ptr != NULL) {
382 struct proxy_entry *ptr_next;
384 ptr_next = ptr->next;
385 if (ptr->rule_index == rule_index) {
396 ProxyEncodeTcpStream(struct alias_link *lnk,
404 /* Compute pointer to tcp header */
405 tc = (struct tcphdr *)ip_next(pip);
407 /* Don't modify if once already modified */
409 if (GetAckModified(lnk))
412 /* Translate destination address and port to string form */
413 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
414 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk)));
416 /* Pad string out to a multiple of two in length */
417 slen = strlen(buffer);
420 strcat(buffer, " \n");
424 strcat(buffer, "\n");
428 /* Check for packet overflow */
429 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
432 /* Shift existing TCP data and insert destination string */
438 hlen = (pip->ip_hl + tc->th_off) << 2;
439 dlen = ntohs(pip->ip_len) - hlen;
441 /* Modify first packet that has data in it */
449 bcopy(p, p + slen, dlen);
450 memcpy(p, buffer, slen);
453 /* Save information about modfied sequence number */
458 delta = GetDeltaSeqOut(pip, lnk);
459 AddSeq(pip, lnk, delta + slen);
462 /* Update IP header packet length and checksum */
466 accumulate = pip->ip_len;
467 pip->ip_len = htons(ntohs(pip->ip_len) + slen);
468 accumulate -= pip->ip_len;
470 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
473 /* Update TCP checksum, Use TcpChecksum since so many things have
477 tc->th_sum = TcpChecksum(pip);
481 ProxyEncodeIpHeader(struct ip *pip,
484 #define OPTION_LEN_BYTES 8
485 #define OPTION_LEN_INT16 4
486 #define OPTION_LEN_INT32 2
487 u_char option[OPTION_LEN_BYTES];
489 #ifdef LIBALIAS_DEBUG
490 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
491 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
496 /* Check to see that there is room to add an IP option */
497 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
500 /* Build option and copy into packet */
505 ptr = (u_char *) pip;
507 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
509 option[0] = 0x64; /* class: 3 (reserved), option 4 */
510 option[1] = OPTION_LEN_BYTES;
512 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
514 tc = (struct tcphdr *)ip_next(pip);
515 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
517 memcpy(ptr, option, 8);
520 /* Update checksum, header length and packet length */
526 sptr = (u_short *) option;
528 for (i = 0; i < OPTION_LEN_INT16; i++)
529 accumulate -= *(sptr++);
531 sptr = (u_short *) pip;
533 pip->ip_hl += OPTION_LEN_INT32;
536 accumulate += pip->ip_len;
537 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
538 accumulate -= pip->ip_len;
540 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
542 #undef OPTION_LEN_BYTES
543 #undef OPTION_LEN_INT16
544 #undef OPTION_LEN_INT32
545 #ifdef LIBALIAS_DEBUG
546 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
547 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
552 /* Functions by other packet alias source files
554 ProxyCheck() -- Checks whether an outgoing packet should
556 ProxyModify() -- Encodes the original destination address/port
557 for a packet which is to be redirected to
562 ProxyCheck(struct libalias *la, struct ip *pip,
563 struct in_addr *proxy_server_addr,
564 u_short * proxy_server_port)
567 struct in_addr src_addr;
568 struct in_addr dst_addr;
569 struct proxy_entry *ptr;
571 src_addr = pip->ip_src;
572 dst_addr = pip->ip_dst;
573 dst_port = ((struct tcphdr *)ip_next(pip))
577 while (ptr != NULL) {
580 proxy_port = ptr->proxy_port;
581 if ((dst_port == proxy_port || proxy_port == 0)
582 && pip->ip_p == ptr->proto
583 && src_addr.s_addr != ptr->server_addr.s_addr) {
584 struct in_addr src_addr_masked;
585 struct in_addr dst_addr_masked;
587 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
588 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
590 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
591 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
592 if ((*proxy_server_port = ptr->server_port) == 0)
593 *proxy_server_port = dst_port;
594 *proxy_server_addr = ptr->server_addr;
595 return (ptr->proxy_type);
605 ProxyModify(struct libalias *la, struct alias_link *lnk,
613 switch (proxy_type) {
614 case PROXY_TYPE_ENCODE_IPHDR:
615 ProxyEncodeIpHeader(pip, maxpacketsize);
618 case PROXY_TYPE_ENCODE_TCPSTREAM:
619 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
630 LibAliasProxyRule(struct libalias *la, const char *cmd)
633 * This function takes command strings of the form:
635 * server <addr>[:<port>]
641 * [type encode_tcp_stream|encode_ip_hdr|no_encode]
643 * delete <rule number>
645 * Subfields can be in arbitrary order. Port numbers and addresses
646 * must be in either numeric or symbolic form. An optional rule number
647 * is used to control the order in which rules are searched. If two
648 * rules have the same number, then search order cannot be guaranteed,
649 * and the rules should be disjoint. If no rule number is specified,
650 * then 0 is used, and group 0 rules are always checked before any
659 char str_port[sizeof(buffer)];
660 char str_server_port[sizeof(buffer)];
668 struct in_addr server_addr;
669 struct in_addr src_addr, src_mask;
670 struct in_addr dst_addr, dst_mask;
671 struct proxy_entry *proxy_entry;
673 /* Copy command line into a buffer */
674 cmd += strspn(cmd, " \t");
675 cmd_len = strlen(cmd);
676 if (cmd_len > (int)(sizeof(buffer) - 1))
680 /* Convert to lower case */
681 len = strlen(buffer);
682 for (i = 0; i < len; i++)
683 buffer[i] = tolower((unsigned char)buffer[i]);
685 /* Set default proxy type */
687 /* Set up default values */
689 proxy_type = PROXY_TYPE_ENCODE_NONE;
692 server_addr.s_addr = 0;
695 IpMask(0, &src_mask);
697 IpMask(0, &dst_mask);
700 str_server_port[0] = 0;
702 /* Parse command string with state machine */
703 #define STATE_READ_KEYWORD 0
704 #define STATE_READ_TYPE 1
705 #define STATE_READ_PORT 2
706 #define STATE_READ_SERVER 3
707 #define STATE_READ_RULE 4
708 #define STATE_READ_DELETE 5
709 #define STATE_READ_PROTO 6
710 #define STATE_READ_SRC 7
711 #define STATE_READ_DST 8
712 state = STATE_READ_KEYWORD;
713 token = strsep(&res, " \t");
715 while (token != NULL) {
718 case STATE_READ_KEYWORD:
719 if (strcmp(token, "type") == 0)
720 state = STATE_READ_TYPE;
721 else if (strcmp(token, "port") == 0)
722 state = STATE_READ_PORT;
723 else if (strcmp(token, "server") == 0)
724 state = STATE_READ_SERVER;
725 else if (strcmp(token, "rule") == 0)
726 state = STATE_READ_RULE;
727 else if (strcmp(token, "delete") == 0)
728 state = STATE_READ_DELETE;
729 else if (strcmp(token, "proto") == 0)
730 state = STATE_READ_PROTO;
731 else if (strcmp(token, "src") == 0)
732 state = STATE_READ_SRC;
733 else if (strcmp(token, "dst") == 0)
734 state = STATE_READ_DST;
739 case STATE_READ_TYPE:
740 if (strcmp(token, "encode_ip_hdr") == 0)
741 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
742 else if (strcmp(token, "encode_tcp_stream") == 0)
743 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
744 else if (strcmp(token, "no_encode") == 0)
745 proxy_type = PROXY_TYPE_ENCODE_NONE;
748 state = STATE_READ_KEYWORD;
751 case STATE_READ_PORT:
752 strcpy(str_port, token);
753 state = STATE_READ_KEYWORD;
756 case STATE_READ_SERVER:
760 char s[sizeof(buffer)];
763 while (*p != ':' && *p != 0)
767 err = IpAddr(token, &server_addr);
773 n = sscanf(token, "%s %s", s, str_server_port);
777 err = IpAddr(s, &server_addr);
782 state = STATE_READ_KEYWORD;
785 case STATE_READ_RULE:
786 n = sscanf(token, "%d", &rule_index);
787 if (n != 1 || rule_index < 0)
789 state = STATE_READ_KEYWORD;
792 case STATE_READ_DELETE:
797 if (token_count != 2)
800 n = sscanf(token, "%d", &rule_to_delete);
803 err = RuleNumberDelete(la, rule_to_delete);
809 case STATE_READ_PROTO:
810 if (strcmp(token, "tcp") == 0)
812 else if (strcmp(token, "udp") == 0)
816 state = STATE_READ_KEYWORD;
828 while (*p != '/' && *p != 0)
833 err = IpAddr(token, &addr);
838 char s[sizeof(buffer)];
841 n = sscanf(token, "%s %d", s, &nbits);
845 err = IpAddr(s, &addr);
849 err = IpMask(nbits, &mask);
854 if (state == STATE_READ_SRC) {
862 state = STATE_READ_KEYWORD;
871 token = strsep(&res, " \t");
872 } while (token != NULL && !*token);
874 #undef STATE_READ_KEYWORD
875 #undef STATE_READ_TYPE
876 #undef STATE_READ_PORT
877 #undef STATE_READ_SERVER
878 #undef STATE_READ_RULE
879 #undef STATE_READ_DELETE
880 #undef STATE_READ_PROTO
881 #undef STATE_READ_SRC
882 #undef STATE_READ_DST
884 /* Convert port strings to numbers. This needs to be done after
885 the string is parsed, because the prototype might not be designated
886 before the ports (which might be symbolic entries in /etc/services) */
888 if (strlen(str_port) != 0) {
891 err = IpPort(str_port, proto, &proxy_port);
898 if (strlen(str_server_port) != 0) {
901 err = IpPort(str_server_port, proto, &server_port);
908 /* Check that at least the server address has been defined */
909 if (server_addr.s_addr == 0)
912 /* Add to linked list */
913 proxy_entry = malloc(sizeof(struct proxy_entry));
914 if (proxy_entry == NULL)
917 proxy_entry->proxy_type = proxy_type;
918 proxy_entry->rule_index = rule_index;
919 proxy_entry->proto = proto;
920 proxy_entry->proxy_port = htons(proxy_port);
921 proxy_entry->server_port = htons(server_port);
922 proxy_entry->server_addr = server_addr;
923 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
924 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
925 proxy_entry->src_mask = src_mask;
926 proxy_entry->dst_mask = dst_mask;
928 RuleAdd(la, proxy_entry);