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: src/sys/netinet/libalias/alias_proxy.c,v 1.31.6.1 2008/11/25 02:59:29 kensmith Exp $");
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>
73 #include "alias.h" /* Public API functions for libalias */
74 #include "alias_local.h" /* Functions used by alias*.c */
75 #include "alias_mod.h"
82 * A linked list of arbitrary length, based on struct proxy_entry is
83 * used to store proxy rules.
87 #define PROXY_TYPE_ENCODE_NONE 1
88 #define PROXY_TYPE_ENCODE_TCPSTREAM 2
89 #define PROXY_TYPE_ENCODE_IPHDR 3
96 struct in_addr server_addr;
98 struct in_addr src_addr;
99 struct in_addr src_mask;
101 struct in_addr dst_addr;
102 struct in_addr dst_mask;
104 struct proxy_entry *next;
105 struct proxy_entry *last;
116 /* Local (static) functions:
118 IpMask() -- Utility function for creating IP
119 masks from integer (1-32) specification.
120 IpAddr() -- Utility function for converting string
122 IpPort() -- Utility function for converting string
124 RuleAdd() -- Adds an element to the rule list.
125 RuleDelete() -- Removes an element from the rule list.
126 RuleNumberDelete() -- Removes all elements from the rule list
127 having a certain rule number.
128 ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning
130 ProxyEncodeIpHeader() -- Adds an IP option indicating the true
131 destination of a proxied IP packet
134 #ifdef _KERNEL /* XXX: can it be moved to libkern? */
135 static int inet_aton(const char *cp, struct in_addr *addr);
137 static int IpMask(int, struct in_addr *);
138 static int IpAddr(char *, struct in_addr *);
139 static int IpPort(char *, int, int *);
140 static void RuleAdd(struct libalias *la, struct proxy_entry *);
141 static void RuleDelete(struct proxy_entry *);
142 static int RuleNumberDelete(struct libalias *la, int);
143 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
144 static void ProxyEncodeIpHeader(struct ip *, int);
149 int inet_aton(const char *cp,struct in_addr *addr)
157 c = (const char *)cp;
160 * Run through the string, grabbing numbers until
161 * the end of the string, or some error
167 l = strtoul(c, &endptr, 0);
169 if (l == ULONG_MAX || (l == 0 && endptr == c))
174 * If the whole string is invalid, endptr will equal
175 * c.. this way we can make sure someone hasn't
176 * gone '.12' or something which would get past
184 /* Check the next character past the previous number's end */
187 /* Make sure we only do 3 dots .. */
188 if (n == 3) /* Whoops. Quit. */
199 if (isspace((unsigned char)*c)) {
203 return (0); /* Invalid character, so fail */
209 * Concoct the address according to
210 * the number of parts specified.
214 case 0: /* a -- 32 bits */
216 * Nothing is necessary here. Overflow checking was
217 * already done in strtoul().
220 case 1: /* a.b -- 8.24 bits */
221 if (val > 0xffffff || parts[0] > 0xff)
223 val |= parts[0] << 24;
226 case 2: /* a.b.c -- 8.8.16 bits */
227 if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
229 val |= (parts[0] << 24) | (parts[1] << 16);
232 case 3: /* a.b.c.d -- 8.8.8.8 bits */
233 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
236 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
241 addr->s_addr = htonl(val);
247 IpMask(int nbits, struct in_addr *mask)
252 if (nbits < 0 || nbits > 32)
256 for (i = 0; i < nbits; i++)
257 imask = (imask >> 1) + 0x80000000;
258 mask->s_addr = htonl(imask);
264 IpAddr(char *s, struct in_addr *addr)
266 if (inet_aton(s, addr) == 0)
273 IpPort(char *s, int proto, int *port)
277 n = ksscanf(s, "%d", port);
279 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */
283 if (proto == IPPROTO_TCP)
284 se = getservbyname(s, "tcp");
285 else if (proto == IPPROTO_UDP)
286 se = getservbyname(s, "udp");
293 *port = (u_int) ntohs(se->s_port);
302 RuleAdd(struct libalias *la, struct proxy_entry *entry)
305 struct proxy_entry *ptr;
306 struct proxy_entry *ptr_last;
308 LIBALIAS_LOCK_ASSERT(la);
310 if (la->proxyList == NULL) {
311 la->proxyList = entry;
318 rule_index = entry->rule_index;
321 while (ptr != NULL) {
322 if (ptr->rule_index >= rule_index) {
323 if (ptr_last == NULL) {
324 entry->next = la->proxyList;
326 la->proxyList->last = entry;
327 la->proxyList = entry;
330 ptr_last->next = entry;
332 entry->last = ptr->last;
340 ptr_last->next = entry;
341 entry->last = ptr_last;
346 RuleDelete(struct proxy_entry *entry)
351 LIBALIAS_LOCK_ASSERT(la);
352 if (entry->last != NULL)
353 entry->last->next = entry->next;
355 la->proxyList = entry->next;
357 if (entry->next != NULL)
358 entry->next->last = entry->last;
360 kfree(entry,M_ALIAS);
364 RuleNumberDelete(struct libalias *la, int rule_index)
367 struct proxy_entry *ptr;
369 LIBALIAS_LOCK_ASSERT(la);
372 while (ptr != NULL) {
373 struct proxy_entry *ptr_next;
375 ptr_next = ptr->next;
376 if (ptr->rule_index == rule_index) {
387 ProxyEncodeTcpStream(struct alias_link *lnk,
395 /* Compute pointer to tcp header */
396 tc = (struct tcphdr *)ip_next(pip);
398 /* Don't modify if once already modified */
400 if (GetAckModified(lnk))
403 /* Translate destination address and port to string form */
404 ksnprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
405 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk)));
407 /* Pad string out to a multiple of two in length */
408 slen = strlen(buffer);
411 strcat(buffer, " \n");
415 strcat(buffer, "\n");
419 /* Check for packet overflow */
420 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
423 /* Shift existing TCP data and insert destination string */
429 hlen = (pip->ip_hl + tc->th_off) << 2;
430 dlen = ntohs(pip->ip_len) - hlen;
432 /* Modify first packet that has data in it */
440 bcopy(p, p + slen, dlen);
441 memcpy(p, buffer, slen);
444 /* Save information about modfied sequence number */
449 delta = GetDeltaSeqOut(pip, lnk);
450 AddSeq(pip, lnk, delta + slen);
453 /* Update IP header packet length and checksum */
457 accumulate = pip->ip_len;
458 pip->ip_len = htons(ntohs(pip->ip_len) + slen);
459 accumulate -= pip->ip_len;
461 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
464 /* Update TCP checksum, Use TcpChecksum since so many things have
471 tc->th_sum = TcpChecksum(pip);
476 ProxyEncodeIpHeader(struct ip *pip,
479 #define OPTION_LEN_BYTES 8
480 #define OPTION_LEN_INT16 4
481 #define OPTION_LEN_INT32 2
482 u_char option[OPTION_LEN_BYTES];
484 #ifdef LIBALIAS_DEBUG
485 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
486 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
491 /* Check to see that there is room to add an IP option */
492 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
495 /* Build option and copy into packet */
500 ptr = (u_char *) pip;
502 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
504 option[0] = 0x64; /* class: 3 (reserved), option 4 */
505 option[1] = OPTION_LEN_BYTES;
507 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
509 tc = (struct tcphdr *)ip_next(pip);
510 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
512 memcpy(ptr, option, 8);
515 /* Update checksum, header length and packet length */
521 sptr = (u_short *) option;
523 for (i = 0; i < OPTION_LEN_INT16; i++)
524 accumulate -= *(sptr++);
526 sptr = (u_short *) pip;
528 pip->ip_hl += OPTION_LEN_INT32;
531 accumulate += pip->ip_len;
532 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
533 accumulate -= pip->ip_len;
535 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
537 #undef OPTION_LEN_BYTES
538 #undef OPTION_LEN_INT16
539 #undef OPTION_LEN_INT32
540 #ifdef LIBALIAS_DEBUG
541 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
542 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
547 /* Functions by other packet alias source files
549 ProxyCheck() -- Checks whether an outgoing packet should
551 ProxyModify() -- Encodes the original destination address/port
552 for a packet which is to be redirected to
557 ProxyCheck(struct libalias *la, struct ip *pip,
558 struct in_addr *proxy_server_addr,
559 u_short * proxy_server_port)
562 struct in_addr src_addr;
563 struct in_addr dst_addr;
564 struct proxy_entry *ptr;
566 LIBALIAS_LOCK_ASSERT(la);
567 src_addr = pip->ip_src;
568 dst_addr = pip->ip_dst;
569 dst_port = ((struct tcphdr *)ip_next(pip))
573 while (ptr != NULL) {
576 proxy_port = ptr->proxy_port;
577 if ((dst_port == proxy_port || proxy_port == 0)
578 && pip->ip_p == ptr->proto
579 && src_addr.s_addr != ptr->server_addr.s_addr) {
580 struct in_addr src_addr_masked;
581 struct in_addr dst_addr_masked;
583 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
584 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
586 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
587 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
588 if ((*proxy_server_port = ptr->server_port) == 0)
589 *proxy_server_port = dst_port;
590 *proxy_server_addr = ptr->server_addr;
591 return (ptr->proxy_type);
601 ProxyModify(struct libalias *la, struct alias_link *lnk,
607 LIBALIAS_LOCK_ASSERT(la);
610 switch (proxy_type) {
611 case PROXY_TYPE_ENCODE_IPHDR:
612 ProxyEncodeIpHeader(pip, maxpacketsize);
615 case PROXY_TYPE_ENCODE_TCPSTREAM:
616 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
627 LibAliasProxyRule(struct libalias *la, const char *cmd)
630 * This function takes command strings of the form:
632 * server <addr>[:<port>]
638 * [type encode_tcp_stream|encode_ip_hdr|no_encode]
640 * delete <rule number>
642 * Subfields can be in arbitrary order. Port numbers and addresses
643 * must be in either numeric or symbolic form. An optional rule number
644 * is used to control the order in which rules are searched. If two
645 * rules have the same number, then search order cannot be guaranteed,
646 * and the rules should be disjoint. If no rule number is specified,
647 * then 0 is used, and group 0 rules are always checked before any
656 char str_port[sizeof(buffer)];
657 char str_server_port[sizeof(buffer)];
665 struct in_addr server_addr;
666 struct in_addr src_addr, src_mask;
667 struct in_addr dst_addr, dst_mask;
668 struct proxy_entry *proxy_entry;
672 /* Copy command line into a buffer */
673 // cmd += strspn(cmd, " \t");
674 cmd_len = strlen(cmd);
675 if (cmd_len > (int)(sizeof(buffer) - 1)) {
681 /* Convert to lower case */
682 len = strlen(buffer);
683 for (i = 0; i < len; i++){
684 buffer[i] = tolower((unsigned char)buffer[i]);
687 /* Set default proxy type */
689 /* Set up default values */
691 proxy_type = PROXY_TYPE_ENCODE_NONE;
694 server_addr.s_addr = 0;
697 IpMask(0, &src_mask);
699 IpMask(0, &dst_mask);
702 str_server_port[0] = 0;
704 /* Parse command string with state machine */
705 #define STATE_READ_KEYWORD 0
706 #define STATE_READ_TYPE 1
707 #define STATE_READ_PORT 2
708 #define STATE_READ_SERVER 3
709 #define STATE_READ_RULE 4
710 #define STATE_READ_DELETE 5
711 #define STATE_READ_PROTO 6
712 #define STATE_READ_SRC 7
713 #define STATE_READ_DST 8
714 state = STATE_READ_KEYWORD;
715 token = strsep(&res, " \t");
717 while (token != NULL) {
720 case STATE_READ_KEYWORD:
721 if (strcmp(token, "type") == 0)
722 state = STATE_READ_TYPE;
723 else if (strcmp(token, "port") == 0)
724 state = STATE_READ_PORT;
725 else if (strcmp(token, "server") == 0)
726 state = STATE_READ_SERVER;
727 else if (strcmp(token, "rule") == 0)
728 state = STATE_READ_RULE;
729 else if (strcmp(token, "delete") == 0)
730 state = STATE_READ_DELETE;
731 else if (strcmp(token, "proto") == 0)
732 state = STATE_READ_PROTO;
733 else if (strcmp(token, "src") == 0)
734 state = STATE_READ_SRC;
735 else if (strcmp(token, "dst") == 0)
736 state = STATE_READ_DST;
743 case STATE_READ_TYPE:
744 if (strcmp(token, "encode_ip_hdr") == 0)
745 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
746 else if (strcmp(token, "encode_tcp_stream") == 0)
747 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
748 else if (strcmp(token, "no_encode") == 0)
749 proxy_type = PROXY_TYPE_ENCODE_NONE;
754 state = STATE_READ_KEYWORD;
757 case STATE_READ_PORT:
758 strcpy(str_port, token);
759 state = STATE_READ_KEYWORD;
762 case STATE_READ_SERVER:
766 char s[sizeof(buffer)];
769 while (*p != ':' && *p != 0)
773 err = IpAddr(token, &server_addr);
781 n = ksscanf(token, "%s %s", s, str_server_port);
787 err = IpAddr(s, &server_addr);
794 state = STATE_READ_KEYWORD;
797 case STATE_READ_RULE:
798 n = ksscanf(token, "%d", &rule_index);
799 if (n != 1 || rule_index < 0) {
803 state = STATE_READ_KEYWORD;
806 case STATE_READ_DELETE:
811 if (token_count != 2) {
816 n = ksscanf(token, "%d", &rule_to_delete);
821 err = RuleNumberDelete(la, rule_to_delete);
828 case STATE_READ_PROTO:
829 if (strcmp(token, "tcp") == 0)
831 else if (strcmp(token, "udp") == 0)
837 state = STATE_READ_KEYWORD;
849 while (*p != '/' && *p != 0)
854 err = IpAddr(token, &addr);
861 char s[sizeof(buffer)];
864 n = ksscanf(token, "%s %d", s, &nbits);
870 err = IpAddr(s, &addr);
876 err = IpMask(nbits, &mask);
883 if (state == STATE_READ_SRC) {
891 state = STATE_READ_KEYWORD;
901 token = strsep(&res, " \t");
902 } while (token != NULL && !*token);
904 #undef STATE_READ_KEYWORD
905 #undef STATE_READ_TYPE
906 #undef STATE_READ_PORT
907 #undef STATE_READ_SERVER
908 #undef STATE_READ_RULE
909 #undef STATE_READ_DELETE
910 #undef STATE_READ_PROTO
911 #undef STATE_READ_SRC
912 #undef STATE_READ_DST
914 /* Convert port strings to numbers. This needs to be done after
915 the string is parsed, because the prototype might not be designated
916 before the ports (which might be symbolic entries in /etc/services) */
918 if (strlen(str_port) != 0) {
921 err = IpPort(str_port, proto, &proxy_port);
930 if (strlen(str_server_port) != 0) {
933 err = IpPort(str_server_port, proto, &server_port);
942 /* Check that at least the server address has been defined */
943 if (server_addr.s_addr == 0) {
948 /* Add to linked list */
949 proxy_entry = kmalloc(sizeof(struct proxy_entry),M_ALIAS, M_WAITOK | M_ZERO);
950 if (proxy_entry == NULL) {
955 proxy_entry->proxy_type = proxy_type;
956 proxy_entry->rule_index = rule_index;
957 proxy_entry->proto = proto;
958 proxy_entry->proxy_port = htons(proxy_port);
959 proxy_entry->server_port = htons(server_port);
960 proxy_entry->server_addr = server_addr;
961 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
962 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
963 proxy_entry->src_mask = src_mask;
964 proxy_entry->dst_mask = dst_mask;
966 RuleAdd(la, proxy_entry);