Merge branch 'vendor/LIBARCHIVE'
[dragonfly.git] / sys / net / libalias / alias_proxy.c
1 /*-
2  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
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 $");
29
30 /* file: alias_proxy.c
31
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.
35
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
41     in the IP header.
42
43     There is one public API function:
44
45         PacketAliasProxyRule()    -- Adds and deletes proxy
46                                      rules.
47
48     Rules are stored in a linear linked list, so lookup efficiency
49     won't be too good for large lists.
50
51
52     Initial development: April, 1998 (cjm)
53 */
54
55
56 /* System includes */
57 #ifdef _KERNEL
58 #include <sys/param.h>
59 #include <sys/ctype.h>
60 #include <sys/libkern.h>
61 #include <sys/limits.h>
62 #else
63 #include <sys/types.h>
64 #include <ctype.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <netdb.h>
68 #include <string.h>
69 #endif
70
71 #include <netinet/tcp.h>
72
73 #include "alias.h"              /* Public API functions for libalias */
74 #include "alias_local.h"        /* Functions used by alias*.c */
75 #include "alias_mod.h"
76
77 /*
78     Data structures
79  */
80
81 /*
82  * A linked list of arbitrary length, based on struct proxy_entry is
83  * used to store proxy rules.
84  */
85 struct proxy_entry {
86         struct libalias *la;
87 #define PROXY_TYPE_ENCODE_NONE      1
88 #define PROXY_TYPE_ENCODE_TCPSTREAM 2
89 #define PROXY_TYPE_ENCODE_IPHDR     3
90         int             rule_index;
91         int             proxy_type;
92         u_char          proto;
93         u_short         proxy_port;
94         u_short         server_port;
95
96         struct in_addr  server_addr;
97
98         struct in_addr  src_addr;
99         struct in_addr  src_mask;
100
101         struct in_addr  dst_addr;
102         struct in_addr  dst_mask;
103
104         struct proxy_entry *next;
105         struct proxy_entry *last;
106 };
107
108
109
110 /*
111     File scope variables
112 */
113
114
115
116 /* Local (static) functions:
117
118     IpMask()                 -- Utility function for creating IP
119                                 masks from integer (1-32) specification.
120     IpAddr()                 -- Utility function for converting string
121                                 to IP address
122     IpPort()                 -- Utility function for converting string
123                                 to port number
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
129                                 of a TCP stream.
130     ProxyEncodeIpHeader()    -- Adds an IP option indicating the true
131                                 destination of a proxied IP packet
132 */
133
134 #ifdef  _KERNEL         /* XXX: can it be moved to libkern? */
135 static int inet_aton(const char *cp, struct in_addr *addr);
136 #endif
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);
145
146 #ifdef  _KERNEL
147
148 //static
149 int inet_aton(const char *cp,struct in_addr *addr)
150 {
151         u_long parts[4];
152         in_addr_t val;
153         const char *c;
154         char *endptr;
155         int gotend, n;
156
157         c = (const char *)cp;
158         n = 0;
159         /*
160          * Run through the string, grabbing numbers until
161          * the end of the string, or some error
162          */
163         gotend = 0;
164         while (!gotend) {
165                 unsigned long l;
166
167                 l = strtoul(c, &endptr, 0);
168
169                 if (l == ULONG_MAX || (l == 0 && endptr == c))
170                         return (0);
171
172                 val = (in_addr_t)l;
173                 /*
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
177                  * the next check.
178                  */
179                 if (endptr == c)
180                         return (0);
181                 parts[n] = val;
182                 c = endptr;
183
184                 /* Check the next character past the previous number's end */
185                 switch (*c) {
186                 case '.' :
187                         /* Make sure we only do 3 dots .. */
188                         if (n == 3)     /* Whoops. Quit. */
189                                 return (0);
190                         n++;
191                         c++;
192                         break;
193
194                 case '\0':
195                         gotend = 1;
196                         break;
197
198                 default:
199                         if (isspace((unsigned char)*c)) {
200                                 gotend = 1;
201                                 break;
202                         } else
203                                 return (0);     /* Invalid character, so fail */
204                 }
205
206         }
207
208         /*
209          * Concoct the address according to
210          * the number of parts specified.
211          */
212
213         switch (n) {
214         case 0:                         /* a -- 32 bits */
215                 /*
216                  * Nothing is necessary here.  Overflow checking was
217                  * already done in strtoul().
218                  */
219                 break;
220         case 1:                         /* a.b -- 8.24 bits */
221                 if (val > 0xffffff || parts[0] > 0xff)
222                         return (0);
223                 val |= parts[0] << 24;
224                 break;
225
226         case 2:                         /* a.b.c -- 8.8.16 bits */
227                 if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff)
228                         return (0);
229                 val |= (parts[0] << 24) | (parts[1] << 16);
230                 break;
231
232         case 3:                         /* a.b.c.d -- 8.8.8.8 bits */
233                 if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff ||
234                     parts[2] > 0xff)
235                         return (0);
236                 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
237                 break;
238         }
239
240         if (addr != NULL)
241                 addr->s_addr = htonl(val);
242         return (1);
243 }
244 #endif
245
246 static int
247 IpMask(int nbits, struct in_addr *mask)
248 {
249         int i;
250         u_int imask;
251
252         if (nbits < 0 || nbits > 32)
253                 return (-1);
254
255         imask = 0;
256         for (i = 0; i < nbits; i++)
257                 imask = (imask >> 1) + 0x80000000;
258         mask->s_addr = htonl(imask);
259
260         return (0);
261 }
262
263 static int
264 IpAddr(char *s, struct in_addr *addr)
265 {
266         if (inet_aton(s, addr) == 0)
267                 return (-1);
268         else
269                 return (0);
270 }
271
272 static int
273 IpPort(char *s, int proto, int *port)
274 {
275         int n;
276
277         n = ksscanf(s, "%d", port);
278         if (n != 1)
279 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */
280         {
281                 struct servent *se;
282
283                 if (proto == IPPROTO_TCP)
284                         se = getservbyname(s, "tcp");
285                 else if (proto == IPPROTO_UDP)
286                         se = getservbyname(s, "udp");
287                 else
288                         return (-1);
289
290                 if (se == NULL)
291                         return (-1);
292
293                 *port = (u_int) ntohs(se->s_port);
294         }
295 #else
296                 return (-1);
297 #endif
298         return (0);
299 }
300
301 void
302 RuleAdd(struct libalias *la, struct proxy_entry *entry)
303 {
304         int rule_index;
305         struct proxy_entry *ptr;
306         struct proxy_entry *ptr_last;
307
308         LIBALIAS_LOCK_ASSERT(la);
309
310         if (la->proxyList == NULL) {
311                 la->proxyList = entry;
312                 entry->last = NULL;
313                 entry->next = NULL;
314                 return;
315         }
316         entry->la = la;
317
318         rule_index = entry->rule_index;
319         ptr = la->proxyList;
320         ptr_last = NULL;
321         while (ptr != NULL) {
322                 if (ptr->rule_index >= rule_index) {
323                         if (ptr_last == NULL) {
324                                 entry->next = la->proxyList;
325                                 entry->last = NULL;
326                                 la->proxyList->last = entry;
327                                 la->proxyList = entry;
328                                 return;
329                         }
330                         ptr_last->next = entry;
331                         ptr->last = entry;
332                         entry->last = ptr->last;
333                         entry->next = ptr;
334                         return;
335                 }
336                 ptr_last = ptr;
337                 ptr = ptr->next;
338         }
339
340         ptr_last->next = entry;
341         entry->last = ptr_last;
342         entry->next = NULL;
343 }
344
345 static void
346 RuleDelete(struct proxy_entry *entry)
347 {
348         struct libalias *la;
349
350         la = entry->la;
351         LIBALIAS_LOCK_ASSERT(la);
352         if (entry->last != NULL)
353                 entry->last->next = entry->next;
354         else
355                 la->proxyList = entry->next;
356
357         if (entry->next != NULL)
358                 entry->next->last = entry->last;
359
360         kfree(entry,M_ALIAS);
361 }
362
363 static int
364 RuleNumberDelete(struct libalias *la, int rule_index)
365 {
366         int err;
367         struct proxy_entry *ptr;
368
369         LIBALIAS_LOCK_ASSERT(la);
370         err = -1;
371         ptr = la->proxyList;
372         while (ptr != NULL) {
373                 struct proxy_entry *ptr_next;
374
375                 ptr_next = ptr->next;
376                 if (ptr->rule_index == rule_index) {
377                         err = 0;
378                         RuleDelete(ptr);
379                 }
380                 ptr = ptr_next;
381         }
382
383         return (err);
384 }
385
386 static void
387 ProxyEncodeTcpStream(struct alias_link *lnk,
388     struct ip *pip,
389     int maxpacketsize)
390 {
391         int slen;
392         char buffer[40];
393         struct tcphdr *tc;
394
395 /* Compute pointer to tcp header */
396         tc = (struct tcphdr *)ip_next(pip);
397
398 /* Don't modify if once already modified */
399
400         if (GetAckModified(lnk))
401                 return;
402
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)));
406
407 /* Pad string out to a multiple of two in length */
408         slen = strlen(buffer);
409         switch (slen % 2) {
410         case 0:
411                 strcat(buffer, " \n");
412                 slen += 2;
413                 break;
414         case 1:
415                 strcat(buffer, "\n");
416                 slen += 1;
417         }
418
419 /* Check for packet overflow */
420         if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
421                 return;
422
423 /* Shift existing TCP data and insert destination string */
424         {
425                 int dlen;
426                 int hlen;
427                 char *p;
428
429                 hlen = (pip->ip_hl + tc->th_off) << 2;
430                 dlen = ntohs(pip->ip_len) - hlen;
431
432 /* Modify first packet that has data in it */
433
434                 if (dlen == 0)
435                         return;
436
437                 p = (char *)pip;
438                 p += hlen;
439
440                 bcopy(p, p + slen, dlen);
441                 memcpy(p, buffer, slen);
442         }
443
444 /* Save information about modfied sequence number */
445         {
446                 int delta;
447
448                 SetAckModified(lnk);
449                 delta = GetDeltaSeqOut(pip, lnk);
450                 AddSeq(pip, lnk, delta + slen);
451         }
452
453 /* Update IP header packet length and checksum */
454         {
455                 int accumulate;
456
457                 accumulate = pip->ip_len;
458                 pip->ip_len = htons(ntohs(pip->ip_len) + slen);
459                 accumulate -= pip->ip_len;
460
461                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
462         }
463
464 /* Update TCP checksum, Use TcpChecksum since so many things have
465    already changed. */
466
467         tc->th_sum = 0;
468 #ifdef _KERNEL
469         tc->th_x2 = 1;
470 #else
471         tc->th_sum = TcpChecksum(pip);
472 #endif
473 }
474
475 static void
476 ProxyEncodeIpHeader(struct ip *pip,
477     int maxpacketsize)
478 {
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];
483
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));
487 #endif
488
489         (void)maxpacketsize;
490
491 /* Check to see that there is room to add an IP option */
492         if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
493                 return;
494
495 /* Build option and copy into packet */
496         {
497                 u_char *ptr;
498                 struct tcphdr *tc;
499
500                 ptr = (u_char *) pip;
501                 ptr += 20;
502                 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
503
504                 option[0] = 0x64;       /* class: 3 (reserved), option 4 */
505                 option[1] = OPTION_LEN_BYTES;
506
507                 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
508
509                 tc = (struct tcphdr *)ip_next(pip);
510                 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
511
512                 memcpy(ptr, option, 8);
513         }
514
515 /* Update checksum, header length and packet length */
516         {
517                 int i;
518                 int accumulate;
519                 u_short *sptr;
520
521                 sptr = (u_short *) option;
522                 accumulate = 0;
523                 for (i = 0; i < OPTION_LEN_INT16; i++)
524                         accumulate -= *(sptr++);
525
526                 sptr = (u_short *) pip;
527                 accumulate += *sptr;
528                 pip->ip_hl += OPTION_LEN_INT32;
529                 accumulate -= *sptr;
530
531                 accumulate += pip->ip_len;
532                 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
533                 accumulate -= pip->ip_len;
534
535                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
536         }
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));
543 #endif
544 }
545
546
547 /* Functions by other packet alias source files
548
549     ProxyCheck()         -- Checks whether an outgoing packet should
550                             be proxied.
551     ProxyModify()        -- Encodes the original destination address/port
552                             for a packet which is to be redirected to
553                             a proxy server.
554 */
555
556 int
557 ProxyCheck(struct libalias *la, struct ip *pip,
558     struct in_addr *proxy_server_addr,
559     u_short * proxy_server_port)
560 {
561         u_short dst_port;
562         struct in_addr src_addr;
563         struct in_addr dst_addr;
564         struct proxy_entry *ptr;
565
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))
570             ->th_dport;
571
572         ptr = la->proxyList;
573         while (ptr != NULL) {
574                 u_short proxy_port;
575
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;
582
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;
585
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);
592                         }
593                 }
594                 ptr = ptr->next;
595         }
596
597         return (0);
598 }
599
600 void
601 ProxyModify(struct libalias *la, struct alias_link *lnk,
602     struct ip *pip,
603     int maxpacketsize,
604     int proxy_type)
605 {
606
607         LIBALIAS_LOCK_ASSERT(la);
608         (void)la;
609
610         switch (proxy_type) {
611                 case PROXY_TYPE_ENCODE_IPHDR:
612                 ProxyEncodeIpHeader(pip, maxpacketsize);
613                 break;
614
615         case PROXY_TYPE_ENCODE_TCPSTREAM:
616                 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
617                 break;
618         }
619 }
620
621
622 /*
623     Public API functions
624 */
625
626 int
627 LibAliasProxyRule(struct libalias *la, const char *cmd)
628 {
629 /*
630  * This function takes command strings of the form:
631  *
632  *   server <addr>[:<port>]
633  *   [port <port>]
634  *   [rule n]
635  *   [proto tcp|udp]
636  *   [src <addr>[/n]]
637  *   [dst <addr>[/n]]
638  *   [type encode_tcp_stream|encode_ip_hdr|no_encode]
639  *
640  *   delete <rule number>
641  *
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
648  * others.
649  */
650         int i, n, len, ret;
651         int cmd_len;
652         int token_count;
653         int state;
654         char *token;
655         char buffer[256];
656         char str_port[sizeof(buffer)];
657         char str_server_port[sizeof(buffer)];
658         char *res = buffer;
659
660         int rule_index;
661         int proto;
662         int proxy_type;
663         int proxy_port;
664         int server_port;
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;
669
670         LIBALIAS_LOCK(la);
671         ret = 0;
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)) {
676                 ret = -1;
677                 goto getout;
678         }
679         strcpy(buffer, cmd);
680
681 /* Convert to lower case */
682         len = strlen(buffer);
683         for (i = 0; i < len; i++){
684                 buffer[i] = tolower((unsigned char)buffer[i]);
685     }
686
687 /* Set default proxy type */
688
689 /* Set up default values */
690         rule_index = 0;
691         proxy_type = PROXY_TYPE_ENCODE_NONE;
692         proto = IPPROTO_TCP;
693         proxy_port = 0;
694         server_addr.s_addr = 0;
695         server_port = 0;
696         src_addr.s_addr = 0;
697         IpMask(0, &src_mask);
698         dst_addr.s_addr = 0;
699         IpMask(0, &dst_mask);
700
701         str_port[0] = 0;
702         str_server_port[0] = 0;
703
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");
716         token_count = 0;
717         while (token != NULL) {
718                 token_count++;
719                 switch (state) {
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;
737                         else {
738                                 ret = -1;
739                                 goto getout;
740                         }
741                         break;
742
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;
750                         else {
751                                 ret = -1;
752                                 goto getout;
753                         }
754                         state = STATE_READ_KEYWORD;
755                         break;
756
757                 case STATE_READ_PORT:
758                         strcpy(str_port, token);
759                         state = STATE_READ_KEYWORD;
760                         break;
761
762                 case STATE_READ_SERVER:
763                         {
764                                 int err;
765                                 char *p;
766                                 char s[sizeof(buffer)];
767
768                                 p = token;
769                                 while (*p != ':' && *p != 0)
770                                         p++;
771
772                                 if (*p != ':') {
773                                         err = IpAddr(token, &server_addr);
774                                         if (err) {
775                                                 ret = -1;
776                                                 goto getout;
777                                         }
778                                 } else {
779                                         *p = ' ';
780
781                                         n = ksscanf(token, "%s %s", s, str_server_port);
782                                         if (n != 2) {
783                                                 ret = -1;
784                                                 goto getout;
785                                         }
786
787                                         err = IpAddr(s, &server_addr);
788                                         if (err) {
789                                                 ret = -1;
790                                                 goto getout;
791                                         }
792                                 }
793                         }
794                         state = STATE_READ_KEYWORD;
795                         break;
796
797                 case STATE_READ_RULE:
798                         n = ksscanf(token, "%d", &rule_index);
799                         if (n != 1 || rule_index < 0) {
800                                 ret = -1;
801                                 goto getout;
802                         }
803                         state = STATE_READ_KEYWORD;
804                         break;
805
806                 case STATE_READ_DELETE:
807                         {
808                                 int err;
809                                 int rule_to_delete;
810
811                                 if (token_count != 2) {
812                                         ret = -1;
813                                         goto getout;
814                                 }
815
816                                 n = ksscanf(token, "%d", &rule_to_delete);
817                                 if (n != 1) {
818                                         ret = -1;
819                                         goto getout;
820                                 }
821                                 err = RuleNumberDelete(la, rule_to_delete);
822                                 if (err)
823                                         ret = -1;
824                                 ret = 0;
825                                 goto getout;
826                         }
827
828                 case STATE_READ_PROTO:
829                         if (strcmp(token, "tcp") == 0)
830                                 proto = IPPROTO_TCP;
831                         else if (strcmp(token, "udp") == 0)
832                                 proto = IPPROTO_UDP;
833                         else {
834                                 ret = -1;
835                                 goto getout;
836                         }
837                         state = STATE_READ_KEYWORD;
838                         break;
839
840                 case STATE_READ_SRC:
841                 case STATE_READ_DST:
842                         {
843                                 int err;
844                                 char *p;
845                                 struct in_addr mask;
846                                 struct in_addr addr;
847
848                                 p = token;
849                                 while (*p != '/' && *p != 0)
850                                         p++;
851
852                                 if (*p != '/') {
853                                         IpMask(32, &mask);
854                                         err = IpAddr(token, &addr);
855                                         if (err) {
856                                                 ret = -1;
857                                                 goto getout;
858                                         }
859                                 } else {
860                                         int nbits;
861                                         char s[sizeof(buffer)];
862
863                                         *p = ' ';
864                                         n = ksscanf(token, "%s %d", s, &nbits);
865                                         if (n != 2) {
866                                                 ret = -1;
867                                                 goto getout;
868                                         }
869
870                                         err = IpAddr(s, &addr);
871                                         if (err) {
872                                                 ret = -1;
873                                                 goto getout;
874                                         }
875
876                                         err = IpMask(nbits, &mask);
877                                         if (err) {
878                                                 ret = -1;
879                                                 goto getout;
880                                         }
881                                 }
882
883                                 if (state == STATE_READ_SRC) {
884                                         src_addr = addr;
885                                         src_mask = mask;
886                                 } else {
887                                         dst_addr = addr;
888                                         dst_mask = mask;
889                                 }
890                         }
891                         state = STATE_READ_KEYWORD;
892                         break;
893
894                 default:
895                         ret = -1;
896                         goto getout;
897                         break;
898                 }
899
900                 do {
901                         token = strsep(&res, " \t");
902                 } while (token != NULL && !*token);
903         }
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
913
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) */
917
918         if (strlen(str_port) != 0) {
919                 int err;
920
921                 err = IpPort(str_port, proto, &proxy_port);
922                 if (err) {
923                         ret = -1;
924                         goto getout;
925                 }
926         } else {
927                 proxy_port = 0;
928         }
929
930         if (strlen(str_server_port) != 0) {
931                 int err;
932
933                 err = IpPort(str_server_port, proto, &server_port);
934                 if (err) {
935                         ret = -1;
936                         goto getout;
937                 }
938         } else {
939                 server_port = 0;
940         }
941
942 /* Check that at least the server address has been defined */
943         if (server_addr.s_addr == 0) {
944                 ret = -1;
945                 goto getout;
946         }
947
948 /* Add to linked list */
949         proxy_entry = kmalloc(sizeof(struct proxy_entry),M_ALIAS, M_WAITOK | M_ZERO);
950         if (proxy_entry == NULL) {
951                 ret = -1;
952                 goto getout;
953         }
954
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;
965
966         RuleAdd(la, proxy_entry);
967
968 getout:
969         LIBALIAS_UNLOCK(la);
970         return (ret);
971 }