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$");
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 #ifdef _KERNEL
74 #include <netinet/libalias/alias.h>
75 #include <netinet/libalias/alias_local.h>
76 #include <netinet/libalias/alias_mod.h>
77 #else
78 #include <arpa/inet.h>
79 #include "alias.h" /* Public API functions for libalias */
80 #include "alias_local.h" /* Functions used by alias*.c */
81 #endif
82
83 /*
84 Data structures
85 */
86
87 /*
88 * A linked list of arbitrary length, based on struct proxy_entry is
89 * used to store proxy rules.
90 */
91 struct proxy_entry {
92 struct libalias *la;
93 #define PROXY_TYPE_ENCODE_NONE 1
94 #define PROXY_TYPE_ENCODE_TCPSTREAM 2
95 #define PROXY_TYPE_ENCODE_IPHDR 3
96 int rule_index;
97 int proxy_type;
98 u_char proto;
99 u_short proxy_port;
100 u_short server_port;
101
102 struct in_addr server_addr;
103
104 struct in_addr src_addr;
105 struct in_addr src_mask;
106
107 struct in_addr dst_addr;
108 struct in_addr dst_mask;
109
110 struct proxy_entry *next;
111 struct proxy_entry *last;
112 };
113
114
115
116 /*
117 File scope variables
118 */
119
120
121
122 /* Local (static) functions:
123
124 IpMask() -- Utility function for creating IP
125 masks from integer (1-32) specification.
126 IpAddr() -- Utility function for converting string
127 to IP address
128 IpPort() -- Utility function for converting string
129 to port number
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
135 of a TCP stream.
136 ProxyEncodeIpHeader() -- Adds an IP option indicating the true
137 destination of a proxied IP packet
138 */
139
140 static int IpMask(int, struct in_addr *);
141 static int IpAddr(char *, struct in_addr *);
142 static int IpPort(char *, int, int *);
143 static void RuleAdd(struct libalias *la, struct proxy_entry *);
144 static void RuleDelete(struct proxy_entry *);
145 static int RuleNumberDelete(struct libalias *la, int);
146 static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int);
147 static void ProxyEncodeIpHeader(struct ip *, int);
148
149 static int
IpMask(int nbits,struct in_addr * mask)150 IpMask(int nbits, struct in_addr *mask)
151 {
152 int i;
153 u_int imask;
154
155 if (nbits < 0 || nbits > 32)
156 return (-1);
157
158 imask = 0;
159 for (i = 0; i < nbits; i++)
160 imask = (imask >> 1) + 0x80000000;
161 mask->s_addr = htonl(imask);
162
163 return (0);
164 }
165
166 static int
IpAddr(char * s,struct in_addr * addr)167 IpAddr(char *s, struct in_addr *addr)
168 {
169 if (inet_aton(s, addr) == 0)
170 return (-1);
171 else
172 return (0);
173 }
174
175 static int
IpPort(char * s,int proto,int * port)176 IpPort(char *s, int proto, int *port)
177 {
178 int n;
179
180 n = sscanf(s, "%d", port);
181 if (n != 1)
182 #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */
183 {
184 struct servent *se;
185
186 if (proto == IPPROTO_TCP)
187 se = getservbyname(s, "tcp");
188 else if (proto == IPPROTO_UDP)
189 se = getservbyname(s, "udp");
190 else
191 return (-1);
192
193 if (se == NULL)
194 return (-1);
195
196 *port = (u_int) ntohs(se->s_port);
197 }
198 #else
199 return (-1);
200 #endif
201 return (0);
202 }
203
204 void
RuleAdd(struct libalias * la,struct proxy_entry * entry)205 RuleAdd(struct libalias *la, struct proxy_entry *entry)
206 {
207 int rule_index;
208 struct proxy_entry *ptr;
209 struct proxy_entry *ptr_last;
210
211 LIBALIAS_LOCK_ASSERT(la);
212
213 entry->la = la;
214 if (la->proxyList == NULL) {
215 la->proxyList = entry;
216 entry->last = NULL;
217 entry->next = NULL;
218 return;
219 }
220
221 rule_index = entry->rule_index;
222 ptr = la->proxyList;
223 ptr_last = NULL;
224 while (ptr != NULL) {
225 if (ptr->rule_index >= rule_index) {
226 if (ptr_last == NULL) {
227 entry->next = la->proxyList;
228 entry->last = NULL;
229 la->proxyList->last = entry;
230 la->proxyList = entry;
231 return;
232 }
233 ptr_last->next = entry;
234 ptr->last = entry;
235 entry->last = ptr->last;
236 entry->next = ptr;
237 return;
238 }
239 ptr_last = ptr;
240 ptr = ptr->next;
241 }
242
243 ptr_last->next = entry;
244 entry->last = ptr_last;
245 entry->next = NULL;
246 }
247
248 static void
RuleDelete(struct proxy_entry * entry)249 RuleDelete(struct proxy_entry *entry)
250 {
251 struct libalias *la;
252
253 la = entry->la;
254 LIBALIAS_LOCK_ASSERT(la);
255 if (entry->last != NULL)
256 entry->last->next = entry->next;
257 else
258 la->proxyList = entry->next;
259
260 if (entry->next != NULL)
261 entry->next->last = entry->last;
262
263 free(entry);
264 }
265
266 static int
RuleNumberDelete(struct libalias * la,int rule_index)267 RuleNumberDelete(struct libalias *la, int rule_index)
268 {
269 int err;
270 struct proxy_entry *ptr;
271
272 LIBALIAS_LOCK_ASSERT(la);
273 err = -1;
274 ptr = la->proxyList;
275 while (ptr != NULL) {
276 struct proxy_entry *ptr_next;
277
278 ptr_next = ptr->next;
279 if (ptr->rule_index == rule_index) {
280 err = 0;
281 RuleDelete(ptr);
282 }
283 ptr = ptr_next;
284 }
285
286 return (err);
287 }
288
289 static void
ProxyEncodeTcpStream(struct alias_link * lnk,struct ip * pip,int maxpacketsize)290 ProxyEncodeTcpStream(struct alias_link *lnk,
291 struct ip *pip,
292 int maxpacketsize)
293 {
294 int slen;
295 char buffer[40];
296 struct tcphdr *tc;
297 char addrbuf[INET_ADDRSTRLEN];
298
299 /* Compute pointer to tcp header */
300 tc = (struct tcphdr *)ip_next(pip);
301
302 /* Don't modify if once already modified */
303
304 if (GetAckModified(lnk))
305 return;
306
307 /* Translate destination address and port to string form */
308 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
309 inet_ntoa_r(GetProxyAddress(lnk), INET_NTOA_BUF(addrbuf)),
310 (u_int) ntohs(GetProxyPort(lnk)));
311
312 /* Pad string out to a multiple of two in length */
313 slen = strlen(buffer);
314 switch (slen % 2) {
315 case 0:
316 strcat(buffer, " \n");
317 slen += 2;
318 break;
319 case 1:
320 strcat(buffer, "\n");
321 slen += 1;
322 }
323
324 /* Check for packet overflow */
325 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
326 return;
327
328 /* Shift existing TCP data and insert destination string */
329 {
330 int dlen;
331 int hlen;
332 char *p;
333
334 hlen = (pip->ip_hl + tc->th_off) << 2;
335 dlen = ntohs(pip->ip_len) - hlen;
336
337 /* Modify first packet that has data in it */
338
339 if (dlen == 0)
340 return;
341
342 p = (char *)pip;
343 p += hlen;
344
345 bcopy(p, p + slen, dlen);
346 memcpy(p, buffer, slen);
347 }
348
349 /* Save information about modfied sequence number */
350 {
351 int delta;
352
353 SetAckModified(lnk);
354 tc = (struct tcphdr *)ip_next(pip);
355 delta = GetDeltaSeqOut(tc->th_seq, lnk);
356 AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
357 tc->th_off);
358 }
359
360 /* Update IP header packet length and checksum */
361 {
362 int accumulate;
363
364 accumulate = pip->ip_len;
365 pip->ip_len = htons(ntohs(pip->ip_len) + slen);
366 accumulate -= pip->ip_len;
367
368 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
369 }
370
371 /* Update TCP checksum, Use TcpChecksum since so many things have
372 already changed. */
373
374 tc->th_sum = 0;
375 #ifdef _KERNEL
376 tc->th_x2 = 1;
377 #else
378 tc->th_sum = TcpChecksum(pip);
379 #endif
380 }
381
382 static void
ProxyEncodeIpHeader(struct ip * pip,int maxpacketsize)383 ProxyEncodeIpHeader(struct ip *pip,
384 int maxpacketsize)
385 {
386 #define OPTION_LEN_BYTES 8
387 #define OPTION_LEN_INT16 4
388 #define OPTION_LEN_INT32 2
389 u_char option[OPTION_LEN_BYTES];
390
391 #ifdef LIBALIAS_DEBUG
392 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
393 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
394 #endif
395
396 (void)maxpacketsize;
397
398 /* Check to see that there is room to add an IP option */
399 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
400 return;
401
402 /* Build option and copy into packet */
403 {
404 u_char *ptr;
405 struct tcphdr *tc;
406
407 ptr = (u_char *) pip;
408 ptr += 20;
409 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
410
411 option[0] = 0x64; /* class: 3 (reserved), option 4 */
412 option[1] = OPTION_LEN_BYTES;
413
414 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
415
416 tc = (struct tcphdr *)ip_next(pip);
417 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
418
419 memcpy(ptr, option, 8);
420 }
421
422 /* Update checksum, header length and packet length */
423 {
424 int i;
425 int accumulate;
426 u_short *sptr;
427
428 sptr = (u_short *) option;
429 accumulate = 0;
430 for (i = 0; i < OPTION_LEN_INT16; i++)
431 accumulate -= *(sptr++);
432
433 sptr = (u_short *) pip;
434 accumulate += *sptr;
435 pip->ip_hl += OPTION_LEN_INT32;
436 accumulate -= *sptr;
437
438 accumulate += pip->ip_len;
439 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
440 accumulate -= pip->ip_len;
441
442 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
443 }
444 #undef OPTION_LEN_BYTES
445 #undef OPTION_LEN_INT16
446 #undef OPTION_LEN_INT32
447 #ifdef LIBALIAS_DEBUG
448 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
449 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
450 #endif
451 }
452
453
454 /* Functions by other packet alias source files
455
456 ProxyCheck() -- Checks whether an outgoing packet should
457 be proxied.
458 ProxyModify() -- Encodes the original destination address/port
459 for a packet which is to be redirected to
460 a proxy server.
461 */
462
463 int
ProxyCheck(struct libalias * la,struct in_addr * proxy_server_addr,u_short * proxy_server_port,struct in_addr src_addr,struct in_addr dst_addr,u_short dst_port,u_char ip_p)464 ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
465 u_short * proxy_server_port, struct in_addr src_addr,
466 struct in_addr dst_addr, u_short dst_port, u_char ip_p)
467 {
468 struct proxy_entry *ptr;
469
470 LIBALIAS_LOCK_ASSERT(la);
471
472 ptr = la->proxyList;
473 while (ptr != NULL) {
474 u_short proxy_port;
475
476 proxy_port = ptr->proxy_port;
477 if ((dst_port == proxy_port || proxy_port == 0)
478 && ip_p == ptr->proto
479 && src_addr.s_addr != ptr->server_addr.s_addr) {
480 struct in_addr src_addr_masked;
481 struct in_addr dst_addr_masked;
482
483 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
484 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
485
486 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
487 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
488 if ((*proxy_server_port = ptr->server_port) == 0)
489 *proxy_server_port = dst_port;
490 *proxy_server_addr = ptr->server_addr;
491 return (ptr->proxy_type);
492 }
493 }
494 ptr = ptr->next;
495 }
496
497 return (0);
498 }
499
500 void
ProxyModify(struct libalias * la,struct alias_link * lnk,struct ip * pip,int maxpacketsize,int proxy_type)501 ProxyModify(struct libalias *la, struct alias_link *lnk,
502 struct ip *pip,
503 int maxpacketsize,
504 int proxy_type)
505 {
506
507 LIBALIAS_LOCK_ASSERT(la);
508 (void)la;
509
510 switch (proxy_type) {
511 case PROXY_TYPE_ENCODE_IPHDR:
512 ProxyEncodeIpHeader(pip, maxpacketsize);
513 break;
514
515 case PROXY_TYPE_ENCODE_TCPSTREAM:
516 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
517 break;
518 }
519 }
520
521
522 /*
523 Public API functions
524 */
525
526 int
LibAliasProxyRule(struct libalias * la,const char * cmd)527 LibAliasProxyRule(struct libalias *la, const char *cmd)
528 {
529 /*
530 * This function takes command strings of the form:
531 *
532 * server <addr>[:<port>]
533 * [port <port>]
534 * [rule n]
535 * [proto tcp|udp]
536 * [src <addr>[/n]]
537 * [dst <addr>[/n]]
538 * [type encode_tcp_stream|encode_ip_hdr|no_encode]
539 *
540 * delete <rule number>
541 *
542 * Subfields can be in arbitrary order. Port numbers and addresses
543 * must be in either numeric or symbolic form. An optional rule number
544 * is used to control the order in which rules are searched. If two
545 * rules have the same number, then search order cannot be guaranteed,
546 * and the rules should be disjoint. If no rule number is specified,
547 * then 0 is used, and group 0 rules are always checked before any
548 * others.
549 */
550 int i, n, len, ret;
551 int cmd_len;
552 int token_count;
553 int state;
554 char *token;
555 char buffer[256];
556 char str_port[sizeof(buffer)];
557 char str_server_port[sizeof(buffer)];
558 char *res = buffer;
559
560 int rule_index;
561 int proto;
562 int proxy_type;
563 int proxy_port;
564 int server_port;
565 struct in_addr server_addr;
566 struct in_addr src_addr, src_mask;
567 struct in_addr dst_addr, dst_mask;
568 struct proxy_entry *proxy_entry;
569
570 LIBALIAS_LOCK(la);
571 ret = 0;
572 /* Copy command line into a buffer */
573 cmd += strspn(cmd, " \t");
574 cmd_len = strlen(cmd);
575 if (cmd_len > (int)(sizeof(buffer) - 1)) {
576 ret = -1;
577 goto getout;
578 }
579 strcpy(buffer, cmd);
580
581 /* Convert to lower case */
582 len = strlen(buffer);
583 for (i = 0; i < len; i++)
584 buffer[i] = tolower((unsigned char)buffer[i]);
585
586 /* Set default proxy type */
587
588 /* Set up default values */
589 rule_index = 0;
590 proxy_type = PROXY_TYPE_ENCODE_NONE;
591 proto = IPPROTO_TCP;
592 proxy_port = 0;
593 server_addr.s_addr = 0;
594 server_port = 0;
595 src_addr.s_addr = 0;
596 IpMask(0, &src_mask);
597 dst_addr.s_addr = 0;
598 IpMask(0, &dst_mask);
599
600 str_port[0] = 0;
601 str_server_port[0] = 0;
602
603 /* Parse command string with state machine */
604 #define STATE_READ_KEYWORD 0
605 #define STATE_READ_TYPE 1
606 #define STATE_READ_PORT 2
607 #define STATE_READ_SERVER 3
608 #define STATE_READ_RULE 4
609 #define STATE_READ_DELETE 5
610 #define STATE_READ_PROTO 6
611 #define STATE_READ_SRC 7
612 #define STATE_READ_DST 8
613 state = STATE_READ_KEYWORD;
614 token = strsep(&res, " \t");
615 token_count = 0;
616 while (token != NULL) {
617 token_count++;
618 switch (state) {
619 case STATE_READ_KEYWORD:
620 if (strcmp(token, "type") == 0)
621 state = STATE_READ_TYPE;
622 else if (strcmp(token, "port") == 0)
623 state = STATE_READ_PORT;
624 else if (strcmp(token, "server") == 0)
625 state = STATE_READ_SERVER;
626 else if (strcmp(token, "rule") == 0)
627 state = STATE_READ_RULE;
628 else if (strcmp(token, "delete") == 0)
629 state = STATE_READ_DELETE;
630 else if (strcmp(token, "proto") == 0)
631 state = STATE_READ_PROTO;
632 else if (strcmp(token, "src") == 0)
633 state = STATE_READ_SRC;
634 else if (strcmp(token, "dst") == 0)
635 state = STATE_READ_DST;
636 else {
637 ret = -1;
638 goto getout;
639 }
640 break;
641
642 case STATE_READ_TYPE:
643 if (strcmp(token, "encode_ip_hdr") == 0)
644 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
645 else if (strcmp(token, "encode_tcp_stream") == 0)
646 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
647 else if (strcmp(token, "no_encode") == 0)
648 proxy_type = PROXY_TYPE_ENCODE_NONE;
649 else {
650 ret = -1;
651 goto getout;
652 }
653 state = STATE_READ_KEYWORD;
654 break;
655
656 case STATE_READ_PORT:
657 strcpy(str_port, token);
658 state = STATE_READ_KEYWORD;
659 break;
660
661 case STATE_READ_SERVER:
662 {
663 int err;
664 char *p;
665 char s[sizeof(buffer)];
666
667 p = token;
668 while (*p != ':' && *p != 0)
669 p++;
670
671 if (*p != ':') {
672 err = IpAddr(token, &server_addr);
673 if (err) {
674 ret = -1;
675 goto getout;
676 }
677 } else {
678 *p = ' ';
679
680 n = sscanf(token, "%s %s", s, str_server_port);
681 if (n != 2) {
682 ret = -1;
683 goto getout;
684 }
685
686 err = IpAddr(s, &server_addr);
687 if (err) {
688 ret = -1;
689 goto getout;
690 }
691 }
692 }
693 state = STATE_READ_KEYWORD;
694 break;
695
696 case STATE_READ_RULE:
697 n = sscanf(token, "%d", &rule_index);
698 if (n != 1 || rule_index < 0) {
699 ret = -1;
700 goto getout;
701 }
702 state = STATE_READ_KEYWORD;
703 break;
704
705 case STATE_READ_DELETE:
706 {
707 int err;
708 int rule_to_delete;
709
710 if (token_count != 2) {
711 ret = -1;
712 goto getout;
713 }
714
715 n = sscanf(token, "%d", &rule_to_delete);
716 if (n != 1) {
717 ret = -1;
718 goto getout;
719 }
720 err = RuleNumberDelete(la, rule_to_delete);
721 if (err)
722 ret = -1;
723 ret = 0;
724 goto getout;
725 }
726
727 case STATE_READ_PROTO:
728 if (strcmp(token, "tcp") == 0)
729 proto = IPPROTO_TCP;
730 else if (strcmp(token, "udp") == 0)
731 proto = IPPROTO_UDP;
732 else {
733 ret = -1;
734 goto getout;
735 }
736 state = STATE_READ_KEYWORD;
737 break;
738
739 case STATE_READ_SRC:
740 case STATE_READ_DST:
741 {
742 int err;
743 char *p;
744 struct in_addr mask;
745 struct in_addr addr;
746
747 p = token;
748 while (*p != '/' && *p != 0)
749 p++;
750
751 if (*p != '/') {
752 IpMask(32, &mask);
753 err = IpAddr(token, &addr);
754 if (err) {
755 ret = -1;
756 goto getout;
757 }
758 } else {
759 int nbits;
760 char s[sizeof(buffer)];
761
762 *p = ' ';
763 n = sscanf(token, "%s %d", s, &nbits);
764 if (n != 2) {
765 ret = -1;
766 goto getout;
767 }
768
769 err = IpAddr(s, &addr);
770 if (err) {
771 ret = -1;
772 goto getout;
773 }
774
775 err = IpMask(nbits, &mask);
776 if (err) {
777 ret = -1;
778 goto getout;
779 }
780 }
781
782 if (state == STATE_READ_SRC) {
783 src_addr = addr;
784 src_mask = mask;
785 } else {
786 dst_addr = addr;
787 dst_mask = mask;
788 }
789 }
790 state = STATE_READ_KEYWORD;
791 break;
792
793 default:
794 ret = -1;
795 goto getout;
796 break;
797 }
798
799 do {
800 token = strsep(&res, " \t");
801 } while (token != NULL && !*token);
802 }
803 #undef STATE_READ_KEYWORD
804 #undef STATE_READ_TYPE
805 #undef STATE_READ_PORT
806 #undef STATE_READ_SERVER
807 #undef STATE_READ_RULE
808 #undef STATE_READ_DELETE
809 #undef STATE_READ_PROTO
810 #undef STATE_READ_SRC
811 #undef STATE_READ_DST
812
813 /* Convert port strings to numbers. This needs to be done after
814 the string is parsed, because the prototype might not be designated
815 before the ports (which might be symbolic entries in /etc/services) */
816
817 if (strlen(str_port) != 0) {
818 int err;
819
820 err = IpPort(str_port, proto, &proxy_port);
821 if (err) {
822 ret = -1;
823 goto getout;
824 }
825 } else {
826 proxy_port = 0;
827 }
828
829 if (strlen(str_server_port) != 0) {
830 int err;
831
832 err = IpPort(str_server_port, proto, &server_port);
833 if (err) {
834 ret = -1;
835 goto getout;
836 }
837 } else {
838 server_port = 0;
839 }
840
841 /* Check that at least the server address has been defined */
842 if (server_addr.s_addr == 0) {
843 ret = -1;
844 goto getout;
845 }
846
847 /* Add to linked list */
848 proxy_entry = malloc(sizeof(struct proxy_entry));
849 if (proxy_entry == NULL) {
850 ret = -1;
851 goto getout;
852 }
853
854 proxy_entry->proxy_type = proxy_type;
855 proxy_entry->rule_index = rule_index;
856 proxy_entry->proto = proto;
857 proxy_entry->proxy_port = htons(proxy_port);
858 proxy_entry->server_port = htons(server_port);
859 proxy_entry->server_addr = server_addr;
860 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
861 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
862 proxy_entry->src_mask = src_mask;
863 proxy_entry->dst_mask = dst_mask;
864
865 RuleAdd(la, proxy_entry);
866
867 getout:
868 LIBALIAS_UNLOCK(la);
869 return (ret);
870 }
871