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