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