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/limits.h>
63 #include <sys/types.h>
71 #include <netinet/tcp.h>
74 #include <netinet/libalias/alias.h>
75 #include <netinet/libalias/alias_local.h>
76 #include <netinet/libalias/alias_mod.h>
78 #include <arpa/inet.h>
79 #include "alias.h" /* Public API functions for libalias */
80 #include "alias_local.h" /* Functions used by alias*.c */
88 * A linked list of arbitrary length, based on struct proxy_entry is
89 * used to store proxy rules.
93 #define PROXY_TYPE_ENCODE_NONE 1
94 #define PROXY_TYPE_ENCODE_TCPSTREAM 2
95 #define PROXY_TYPE_ENCODE_IPHDR 3
102 struct in_addr server_addr;
104 struct in_addr src_addr;
105 struct in_addr src_mask;
107 struct in_addr dst_addr;
108 struct in_addr dst_mask;
110 struct proxy_entry *next;
111 struct proxy_entry *last;
122 /* Local (static) functions:
124 IpMask() -- Utility function for creating IP
125 masks from integer (1-32) specification.
126 IpAddr() -- Utility function for converting string
128 IpPort() -- Utility function for converting string
130 RuleAdd() -- Adds an element to the rule list.
131 RuleDelete() -- Removes an element from the rule list.
132 RuleNumberDelete() -- Removes all elements from the rule list
133 having a certain rule number.
134 ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning
136 ProxyEncodeIpHeader() -- Adds an IP option indicating the true
137 destination of a proxied IP packet
140 #ifdef _KERNEL /* XXX: can it be moved to libkern? */
141 static int inet_aton(const char *cp, struct in_addr *addr);
143 static int IpMask(int, struct in_addr *);
144 static int IpAddr(char *, struct in_addr *);
145 static int IpPort(char *, int, int *);
146 static void RuleAdd(struct libalias *la, struct proxy_entry *);
147 static void RuleDelete(struct proxy_entry *);
148 static int RuleNumberDelete(struct libalias *la, int);
149 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
150 static void ProxyEncodeIpHeader(struct ip *, int);
156 struct in_addr *addr;
164 c = (const char *)cp;
167 * Run through the string, grabbing numbers until
168 * the end of the string, or some error
174 l = strtoul(c, &endptr, 0);
176 if (l == ULONG_MAX || (l == 0 && endptr == c))
181 * If the whole string is invalid, endptr will equal
182 * c.. this way we can make sure someone hasn't
183 * gone '.12' or something which would get past
191 /* Check the next character past the previous number's end */
194 /* Make sure we only do 3 dots .. */
195 if (n == 3) /* Whoops. Quit. */
206 if (isspace((unsigned char)*c)) {
210 return (0); /* Invalid character, so fail */
216 * Concoct the address according to
217 * the number of parts specified.
221 case 0: /* a -- 32 bits */
223 * Nothing is necessary here. Overflow checking was
224 * already done in strtoul().
227 case 1: /* a.b -- 8.24 bits */
228 if (val > 0xffffff || parts[0] > 0xff)
230 val |= parts[0] << 24;
233 case 2: /* a.b.c -- 8.8.16 bits */
234 if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
236 val |= (parts[0] << 24) | (parts[1] << 16);
239 case 3: /* a.b.c.d -- 8.8.8.8 bits */
240 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
243 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
248 addr->s_addr = htonl(val);
254 IpMask(int nbits, struct in_addr *mask)
259 if (nbits < 0 || nbits > 32)
263 for (i = 0; i < nbits; i++)
264 imask = (imask >> 1) + 0x80000000;
265 mask->s_addr = htonl(imask);
271 IpAddr(char *s, struct in_addr *addr)
273 if (inet_aton(s, addr) == 0)
280 IpPort(char *s, int proto, int *port)
284 n = sscanf(s, "%d", port);
286 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */
290 if (proto == IPPROTO_TCP)
291 se = getservbyname(s, "tcp");
292 else if (proto == IPPROTO_UDP)
293 se = getservbyname(s, "udp");
300 *port = (u_int) ntohs(se->s_port);
309 RuleAdd(struct libalias *la, struct proxy_entry *entry)
312 struct proxy_entry *ptr;
313 struct proxy_entry *ptr_last;
315 LIBALIAS_LOCK_ASSERT(la);
317 if (la->proxyList == NULL) {
318 la->proxyList = entry;
325 rule_index = entry->rule_index;
328 while (ptr != NULL) {
329 if (ptr->rule_index >= rule_index) {
330 if (ptr_last == NULL) {
331 entry->next = la->proxyList;
333 la->proxyList->last = entry;
334 la->proxyList = entry;
337 ptr_last->next = entry;
339 entry->last = ptr->last;
347 ptr_last->next = entry;
348 entry->last = ptr_last;
353 RuleDelete(struct proxy_entry *entry)
358 LIBALIAS_LOCK_ASSERT(la);
359 if (entry->last != NULL)
360 entry->last->next = entry->next;
362 la->proxyList = entry->next;
364 if (entry->next != NULL)
365 entry->next->last = entry->last;
371 RuleNumberDelete(struct libalias *la, int rule_index)
374 struct proxy_entry *ptr;
376 LIBALIAS_LOCK_ASSERT(la);
379 while (ptr != NULL) {
380 struct proxy_entry *ptr_next;
382 ptr_next = ptr->next;
383 if (ptr->rule_index == rule_index) {
394 ProxyEncodeTcpStream(struct alias_link *lnk,
402 /* Compute pointer to tcp header */
403 tc = (struct tcphdr *)ip_next(pip);
405 /* Don't modify if once already modified */
407 if (GetAckModified(lnk))
410 /* Translate destination address and port to string form */
411 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
412 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk)));
414 /* Pad string out to a multiple of two in length */
415 slen = strlen(buffer);
418 strcat(buffer, " \n");
422 strcat(buffer, "\n");
426 /* Check for packet overflow */
427 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
430 /* Shift existing TCP data and insert destination string */
436 hlen = (pip->ip_hl + tc->th_off) << 2;
437 dlen = ntohs(pip->ip_len) - hlen;
439 /* Modify first packet that has data in it */
447 bcopy(p, p + slen, dlen);
448 memcpy(p, buffer, slen);
451 /* Save information about modfied sequence number */
456 tc = (struct tcphdr *)ip_next(pip);
457 delta = GetDeltaSeqOut(tc->th_seq, lnk);
458 AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
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
480 tc->th_sum = TcpChecksum(pip);
485 ProxyEncodeIpHeader(struct ip *pip,
488 #define OPTION_LEN_BYTES 8
489 #define OPTION_LEN_INT16 4
490 #define OPTION_LEN_INT32 2
491 u_char option[OPTION_LEN_BYTES];
493 #ifdef LIBALIAS_DEBUG
494 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
495 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
500 /* Check to see that there is room to add an IP option */
501 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
504 /* Build option and copy into packet */
509 ptr = (u_char *) pip;
511 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
513 option[0] = 0x64; /* class: 3 (reserved), option 4 */
514 option[1] = OPTION_LEN_BYTES;
516 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
518 tc = (struct tcphdr *)ip_next(pip);
519 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
521 memcpy(ptr, option, 8);
524 /* Update checksum, header length and packet length */
530 sptr = (u_short *) option;
532 for (i = 0; i < OPTION_LEN_INT16; i++)
533 accumulate -= *(sptr++);
535 sptr = (u_short *) pip;
537 pip->ip_hl += OPTION_LEN_INT32;
540 accumulate += pip->ip_len;
541 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
542 accumulate -= pip->ip_len;
544 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
546 #undef OPTION_LEN_BYTES
547 #undef OPTION_LEN_INT16
548 #undef OPTION_LEN_INT32
549 #ifdef LIBALIAS_DEBUG
550 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
551 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
556 /* Functions by other packet alias source files
558 ProxyCheck() -- Checks whether an outgoing packet should
560 ProxyModify() -- Encodes the original destination address/port
561 for a packet which is to be redirected to
566 ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
567 u_short * proxy_server_port, struct in_addr src_addr,
568 struct in_addr dst_addr, u_short dst_port, u_char ip_p)
570 struct proxy_entry *ptr;
572 LIBALIAS_LOCK_ASSERT(la);
575 while (ptr != NULL) {
578 proxy_port = ptr->proxy_port;
579 if ((dst_port == proxy_port || proxy_port == 0)
580 && ip_p == ptr->proto
581 && src_addr.s_addr != ptr->server_addr.s_addr) {
582 struct in_addr src_addr_masked;
583 struct in_addr dst_addr_masked;
585 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
586 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
588 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
589 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
590 if ((*proxy_server_port = ptr->server_port) == 0)
591 *proxy_server_port = dst_port;
592 *proxy_server_addr = ptr->server_addr;
593 return (ptr->proxy_type);
603 ProxyModify(struct libalias *la, struct alias_link *lnk,
609 LIBALIAS_LOCK_ASSERT(la);
612 switch (proxy_type) {
613 case PROXY_TYPE_ENCODE_IPHDR:
614 ProxyEncodeIpHeader(pip, maxpacketsize);
617 case PROXY_TYPE_ENCODE_TCPSTREAM:
618 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
629 LibAliasProxyRule(struct libalias *la, const char *cmd)
632 * This function takes command strings of the form:
634 * server <addr>[:<port>]
640 * [type encode_tcp_stream|encode_ip_hdr|no_encode]
642 * delete <rule number>
644 * Subfields can be in arbitrary order. Port numbers and addresses
645 * must be in either numeric or symbolic form. An optional rule number
646 * is used to control the order in which rules are searched. If two
647 * rules have the same number, then search order cannot be guaranteed,
648 * and the rules should be disjoint. If no rule number is specified,
649 * then 0 is used, and group 0 rules are always checked before any
658 char str_port[sizeof(buffer)];
659 char str_server_port[sizeof(buffer)];
667 struct in_addr server_addr;
668 struct in_addr src_addr, src_mask;
669 struct in_addr dst_addr, dst_mask;
670 struct proxy_entry *proxy_entry;
674 /* Copy command line into a buffer */
675 cmd += strspn(cmd, " \t");
676 cmd_len = strlen(cmd);
677 if (cmd_len > (int)(sizeof(buffer) - 1)) {
683 /* Convert to lower case */
684 len = strlen(buffer);
685 for (i = 0; i < len; i++)
686 buffer[i] = tolower((unsigned char)buffer[i]);
688 /* Set default proxy type */
690 /* Set up default values */
692 proxy_type = PROXY_TYPE_ENCODE_NONE;
695 server_addr.s_addr = 0;
698 IpMask(0, &src_mask);
700 IpMask(0, &dst_mask);
703 str_server_port[0] = 0;
705 /* Parse command string with state machine */
706 #define STATE_READ_KEYWORD 0
707 #define STATE_READ_TYPE 1
708 #define STATE_READ_PORT 2
709 #define STATE_READ_SERVER 3
710 #define STATE_READ_RULE 4
711 #define STATE_READ_DELETE 5
712 #define STATE_READ_PROTO 6
713 #define STATE_READ_SRC 7
714 #define STATE_READ_DST 8
715 state = STATE_READ_KEYWORD;
716 token = strsep(&res, " \t");
718 while (token != NULL) {
721 case STATE_READ_KEYWORD:
722 if (strcmp(token, "type") == 0)
723 state = STATE_READ_TYPE;
724 else if (strcmp(token, "port") == 0)
725 state = STATE_READ_PORT;
726 else if (strcmp(token, "server") == 0)
727 state = STATE_READ_SERVER;
728 else if (strcmp(token, "rule") == 0)
729 state = STATE_READ_RULE;
730 else if (strcmp(token, "delete") == 0)
731 state = STATE_READ_DELETE;
732 else if (strcmp(token, "proto") == 0)
733 state = STATE_READ_PROTO;
734 else if (strcmp(token, "src") == 0)
735 state = STATE_READ_SRC;
736 else if (strcmp(token, "dst") == 0)
737 state = STATE_READ_DST;
744 case STATE_READ_TYPE:
745 if (strcmp(token, "encode_ip_hdr") == 0)
746 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
747 else if (strcmp(token, "encode_tcp_stream") == 0)
748 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
749 else if (strcmp(token, "no_encode") == 0)
750 proxy_type = PROXY_TYPE_ENCODE_NONE;
755 state = STATE_READ_KEYWORD;
758 case STATE_READ_PORT:
759 strcpy(str_port, token);
760 state = STATE_READ_KEYWORD;
763 case STATE_READ_SERVER:
767 char s[sizeof(buffer)];
770 while (*p != ':' && *p != 0)
774 err = IpAddr(token, &server_addr);
782 n = sscanf(token, "%s %s", s, str_server_port);
788 err = IpAddr(s, &server_addr);
795 state = STATE_READ_KEYWORD;
798 case STATE_READ_RULE:
799 n = sscanf(token, "%d", &rule_index);
800 if (n != 1 || rule_index < 0) {
804 state = STATE_READ_KEYWORD;
807 case STATE_READ_DELETE:
812 if (token_count != 2) {
817 n = sscanf(token, "%d", &rule_to_delete);
822 err = RuleNumberDelete(la, rule_to_delete);
829 case STATE_READ_PROTO:
830 if (strcmp(token, "tcp") == 0)
832 else if (strcmp(token, "udp") == 0)
838 state = STATE_READ_KEYWORD;
850 while (*p != '/' && *p != 0)
855 err = IpAddr(token, &addr);
862 char s[sizeof(buffer)];
865 n = sscanf(token, "%s %d", s, &nbits);
871 err = IpAddr(s, &addr);
877 err = IpMask(nbits, &mask);
884 if (state == STATE_READ_SRC) {
892 state = STATE_READ_KEYWORD;
902 token = strsep(&res, " \t");
903 } while (token != NULL && !*token);
905 #undef STATE_READ_KEYWORD
906 #undef STATE_READ_TYPE
907 #undef STATE_READ_PORT
908 #undef STATE_READ_SERVER
909 #undef STATE_READ_RULE
910 #undef STATE_READ_DELETE
911 #undef STATE_READ_PROTO
912 #undef STATE_READ_SRC
913 #undef STATE_READ_DST
915 /* Convert port strings to numbers. This needs to be done after
916 the string is parsed, because the prototype might not be designated
917 before the ports (which might be symbolic entries in /etc/services) */
919 if (strlen(str_port) != 0) {
922 err = IpPort(str_port, proto, &proxy_port);
931 if (strlen(str_server_port) != 0) {
934 err = IpPort(str_server_port, proto, &server_port);
943 /* Check that at least the server address has been defined */
944 if (server_addr.s_addr == 0) {
949 /* Add to linked list */
950 proxy_entry = malloc(sizeof(struct proxy_entry));
951 if (proxy_entry == NULL) {
956 proxy_entry->proxy_type = proxy_type;
957 proxy_entry->rule_index = rule_index;
958 proxy_entry->proto = proto;
959 proxy_entry->proxy_port = htons(proxy_port);
960 proxy_entry->server_port = htons(server_port);
961 proxy_entry->server_addr = server_addr;
962 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
963 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
964 proxy_entry->src_mask = src_mask;
965 proxy_entry->dst_mask = dst_mask;
967 RuleAdd(la, proxy_entry);