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