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 delta = GetDeltaSeqOut(pip, lnk);
457 AddSeq(pip, lnk, delta + slen);
460 /* Update IP header packet length and checksum */
464 accumulate = pip->ip_len;
465 pip->ip_len = htons(ntohs(pip->ip_len) + slen);
466 accumulate -= pip->ip_len;
468 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
471 /* Update TCP checksum, Use TcpChecksum since so many things have
478 tc->th_sum = TcpChecksum(pip);
483 ProxyEncodeIpHeader(struct ip *pip,
486 #define OPTION_LEN_BYTES 8
487 #define OPTION_LEN_INT16 4
488 #define OPTION_LEN_INT32 2
489 u_char option[OPTION_LEN_BYTES];
491 #ifdef LIBALIAS_DEBUG
492 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
493 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
498 /* Check to see that there is room to add an IP option */
499 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
502 /* Build option and copy into packet */
507 ptr = (u_char *) pip;
509 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
511 option[0] = 0x64; /* class: 3 (reserved), option 4 */
512 option[1] = OPTION_LEN_BYTES;
514 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
516 tc = (struct tcphdr *)ip_next(pip);
517 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
519 memcpy(ptr, option, 8);
522 /* Update checksum, header length and packet length */
528 sptr = (u_short *) option;
530 for (i = 0; i < OPTION_LEN_INT16; i++)
531 accumulate -= *(sptr++);
533 sptr = (u_short *) pip;
535 pip->ip_hl += OPTION_LEN_INT32;
538 accumulate += pip->ip_len;
539 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
540 accumulate -= pip->ip_len;
542 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
544 #undef OPTION_LEN_BYTES
545 #undef OPTION_LEN_INT16
546 #undef OPTION_LEN_INT32
547 #ifdef LIBALIAS_DEBUG
548 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
549 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
554 /* Functions by other packet alias source files
556 ProxyCheck() -- Checks whether an outgoing packet should
558 ProxyModify() -- Encodes the original destination address/port
559 for a packet which is to be redirected to
564 ProxyCheck(struct libalias *la, struct ip *pip,
565 struct in_addr *proxy_server_addr,
566 u_short * proxy_server_port)
569 struct in_addr src_addr;
570 struct in_addr dst_addr;
571 struct proxy_entry *ptr;
573 LIBALIAS_LOCK_ASSERT(la);
574 src_addr = pip->ip_src;
575 dst_addr = pip->ip_dst;
576 dst_port = ((struct tcphdr *)ip_next(pip))
580 while (ptr != NULL) {
583 proxy_port = ptr->proxy_port;
584 if ((dst_port == proxy_port || proxy_port == 0)
585 && pip->ip_p == ptr->proto
586 && src_addr.s_addr != ptr->server_addr.s_addr) {
587 struct in_addr src_addr_masked;
588 struct in_addr dst_addr_masked;
590 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
591 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
593 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
594 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
595 if ((*proxy_server_port = ptr->server_port) == 0)
596 *proxy_server_port = dst_port;
597 *proxy_server_addr = ptr->server_addr;
598 return (ptr->proxy_type);
608 ProxyModify(struct libalias *la, struct alias_link *lnk,
614 LIBALIAS_LOCK_ASSERT(la);
617 switch (proxy_type) {
618 case PROXY_TYPE_ENCODE_IPHDR:
619 ProxyEncodeIpHeader(pip, maxpacketsize);
622 case PROXY_TYPE_ENCODE_TCPSTREAM:
623 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
634 LibAliasProxyRule(struct libalias *la, const char *cmd)
637 * This function takes command strings of the form:
639 * server <addr>[:<port>]
645 * [type encode_tcp_stream|encode_ip_hdr|no_encode]
647 * delete <rule number>
649 * Subfields can be in arbitrary order. Port numbers and addresses
650 * must be in either numeric or symbolic form. An optional rule number
651 * is used to control the order in which rules are searched. If two
652 * rules have the same number, then search order cannot be guaranteed,
653 * and the rules should be disjoint. If no rule number is specified,
654 * then 0 is used, and group 0 rules are always checked before any
663 char str_port[sizeof(buffer)];
664 char str_server_port[sizeof(buffer)];
672 struct in_addr server_addr;
673 struct in_addr src_addr, src_mask;
674 struct in_addr dst_addr, dst_mask;
675 struct proxy_entry *proxy_entry;
679 /* Copy command line into a buffer */
680 cmd += strspn(cmd, " \t");
681 cmd_len = strlen(cmd);
682 if (cmd_len > (int)(sizeof(buffer) - 1)) {
688 /* Convert to lower case */
689 len = strlen(buffer);
690 for (i = 0; i < len; i++)
691 buffer[i] = tolower((unsigned char)buffer[i]);
693 /* Set default proxy type */
695 /* Set up default values */
697 proxy_type = PROXY_TYPE_ENCODE_NONE;
700 server_addr.s_addr = 0;
703 IpMask(0, &src_mask);
705 IpMask(0, &dst_mask);
708 str_server_port[0] = 0;
710 /* Parse command string with state machine */
711 #define STATE_READ_KEYWORD 0
712 #define STATE_READ_TYPE 1
713 #define STATE_READ_PORT 2
714 #define STATE_READ_SERVER 3
715 #define STATE_READ_RULE 4
716 #define STATE_READ_DELETE 5
717 #define STATE_READ_PROTO 6
718 #define STATE_READ_SRC 7
719 #define STATE_READ_DST 8
720 state = STATE_READ_KEYWORD;
721 token = strsep(&res, " \t");
723 while (token != NULL) {
726 case STATE_READ_KEYWORD:
727 if (strcmp(token, "type") == 0)
728 state = STATE_READ_TYPE;
729 else if (strcmp(token, "port") == 0)
730 state = STATE_READ_PORT;
731 else if (strcmp(token, "server") == 0)
732 state = STATE_READ_SERVER;
733 else if (strcmp(token, "rule") == 0)
734 state = STATE_READ_RULE;
735 else if (strcmp(token, "delete") == 0)
736 state = STATE_READ_DELETE;
737 else if (strcmp(token, "proto") == 0)
738 state = STATE_READ_PROTO;
739 else if (strcmp(token, "src") == 0)
740 state = STATE_READ_SRC;
741 else if (strcmp(token, "dst") == 0)
742 state = STATE_READ_DST;
749 case STATE_READ_TYPE:
750 if (strcmp(token, "encode_ip_hdr") == 0)
751 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
752 else if (strcmp(token, "encode_tcp_stream") == 0)
753 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
754 else if (strcmp(token, "no_encode") == 0)
755 proxy_type = PROXY_TYPE_ENCODE_NONE;
760 state = STATE_READ_KEYWORD;
763 case STATE_READ_PORT:
764 strcpy(str_port, token);
765 state = STATE_READ_KEYWORD;
768 case STATE_READ_SERVER:
772 char s[sizeof(buffer)];
775 while (*p != ':' && *p != 0)
779 err = IpAddr(token, &server_addr);
787 n = sscanf(token, "%s %s", s, str_server_port);
793 err = IpAddr(s, &server_addr);
800 state = STATE_READ_KEYWORD;
803 case STATE_READ_RULE:
804 n = sscanf(token, "%d", &rule_index);
805 if (n != 1 || rule_index < 0) {
809 state = STATE_READ_KEYWORD;
812 case STATE_READ_DELETE:
817 if (token_count != 2) {
822 n = sscanf(token, "%d", &rule_to_delete);
827 err = RuleNumberDelete(la, rule_to_delete);
834 case STATE_READ_PROTO:
835 if (strcmp(token, "tcp") == 0)
837 else if (strcmp(token, "udp") == 0)
843 state = STATE_READ_KEYWORD;
855 while (*p != '/' && *p != 0)
860 err = IpAddr(token, &addr);
867 char s[sizeof(buffer)];
870 n = sscanf(token, "%s %d", s, &nbits);
876 err = IpAddr(s, &addr);
882 err = IpMask(nbits, &mask);
889 if (state == STATE_READ_SRC) {
897 state = STATE_READ_KEYWORD;
907 token = strsep(&res, " \t");
908 } while (token != NULL && !*token);
910 #undef STATE_READ_KEYWORD
911 #undef STATE_READ_TYPE
912 #undef STATE_READ_PORT
913 #undef STATE_READ_SERVER
914 #undef STATE_READ_RULE
915 #undef STATE_READ_DELETE
916 #undef STATE_READ_PROTO
917 #undef STATE_READ_SRC
918 #undef STATE_READ_DST
920 /* Convert port strings to numbers. This needs to be done after
921 the string is parsed, because the prototype might not be designated
922 before the ports (which might be symbolic entries in /etc/services) */
924 if (strlen(str_port) != 0) {
927 err = IpPort(str_port, proto, &proxy_port);
936 if (strlen(str_server_port) != 0) {
939 err = IpPort(str_server_port, proto, &server_port);
948 /* Check that at least the server address has been defined */
949 if (server_addr.s_addr == 0) {
954 /* Add to linked list */
955 proxy_entry = malloc(sizeof(struct proxy_entry));
956 if (proxy_entry == NULL) {
961 proxy_entry->proxy_type = proxy_type;
962 proxy_entry->rule_index = rule_index;
963 proxy_entry->proto = proto;
964 proxy_entry->proxy_port = htons(proxy_port);
965 proxy_entry->server_port = htons(server_port);
966 proxy_entry->server_addr = server_addr;
967 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
968 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
969 proxy_entry->src_mask = src_mask;
970 proxy_entry->dst_mask = dst_mask;
972 RuleAdd(la, proxy_entry);