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
298 /* Compute pointer to tcp header */
299 tc = (struct tcphdr *)ip_next(pip);
300
301 /* Don't modify if once already modified */
302
303 if (GetAckModified(lnk))
304 return;
305
306 /* Translate destination address and port to string form */
307 snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]",
308 inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk)));
309
310 /* Pad string out to a multiple of two in length */
311 slen = strlen(buffer);
312 switch (slen % 2) {
313 case 0:
314 strcat(buffer, " \n");
315 slen += 2;
316 break;
317 case 1:
318 strcat(buffer, "\n");
319 slen += 1;
320 }
321
322 /* Check for packet overflow */
323 if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize)
324 return;
325
326 /* Shift existing TCP data and insert destination string */
327 {
328 int dlen;
329 int hlen;
330 char *p;
331
332 hlen = (pip->ip_hl + tc->th_off) << 2;
333 dlen = ntohs(pip->ip_len) - hlen;
334
335 /* Modify first packet that has data in it */
336
337 if (dlen == 0)
338 return;
339
340 p = (char *)pip;
341 p += hlen;
342
343 bcopy(p, p + slen, dlen);
344 memcpy(p, buffer, slen);
345 }
346
347 /* Save information about modfied sequence number */
348 {
349 int delta;
350
351 SetAckModified(lnk);
352 tc = (struct tcphdr *)ip_next(pip);
353 delta = GetDeltaSeqOut(tc->th_seq, lnk);
354 AddSeq(lnk, delta + slen, pip->ip_hl, pip->ip_len, tc->th_seq,
355 tc->th_off);
356 }
357
358 /* Update IP header packet length and checksum */
359 {
360 int accumulate;
361
362 accumulate = pip->ip_len;
363 pip->ip_len = htons(ntohs(pip->ip_len) + slen);
364 accumulate -= pip->ip_len;
365
366 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
367 }
368
369 /* Update TCP checksum, Use TcpChecksum since so many things have
370 already changed. */
371
372 tc->th_sum = 0;
373 #ifdef _KERNEL
374 tc->th_x2 = 1;
375 #else
376 tc->th_sum = TcpChecksum(pip);
377 #endif
378 }
379
380 static void
ProxyEncodeIpHeader(struct ip * pip,int maxpacketsize)381 ProxyEncodeIpHeader(struct ip *pip,
382 int maxpacketsize)
383 {
384 #define OPTION_LEN_BYTES 8
385 #define OPTION_LEN_INT16 4
386 #define OPTION_LEN_INT32 2
387 u_char option[OPTION_LEN_BYTES];
388
389 #ifdef LIBALIAS_DEBUG
390 fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip));
391 fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip));
392 #endif
393
394 (void)maxpacketsize;
395
396 /* Check to see that there is room to add an IP option */
397 if (pip->ip_hl > (0x0f - OPTION_LEN_INT32))
398 return;
399
400 /* Build option and copy into packet */
401 {
402 u_char *ptr;
403 struct tcphdr *tc;
404
405 ptr = (u_char *) pip;
406 ptr += 20;
407 memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20);
408
409 option[0] = 0x64; /* class: 3 (reserved), option 4 */
410 option[1] = OPTION_LEN_BYTES;
411
412 memcpy(&option[2], (u_char *) & pip->ip_dst, 4);
413
414 tc = (struct tcphdr *)ip_next(pip);
415 memcpy(&option[6], (u_char *) & tc->th_sport, 2);
416
417 memcpy(ptr, option, 8);
418 }
419
420 /* Update checksum, header length and packet length */
421 {
422 int i;
423 int accumulate;
424 u_short *sptr;
425
426 sptr = (u_short *) option;
427 accumulate = 0;
428 for (i = 0; i < OPTION_LEN_INT16; i++)
429 accumulate -= *(sptr++);
430
431 sptr = (u_short *) pip;
432 accumulate += *sptr;
433 pip->ip_hl += OPTION_LEN_INT32;
434 accumulate -= *sptr;
435
436 accumulate += pip->ip_len;
437 pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES);
438 accumulate -= pip->ip_len;
439
440 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
441 }
442 #undef OPTION_LEN_BYTES
443 #undef OPTION_LEN_INT16
444 #undef OPTION_LEN_INT32
445 #ifdef LIBALIAS_DEBUG
446 fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip));
447 fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip));
448 #endif
449 }
450
451
452 /* Functions by other packet alias source files
453
454 ProxyCheck() -- Checks whether an outgoing packet should
455 be proxied.
456 ProxyModify() -- Encodes the original destination address/port
457 for a packet which is to be redirected to
458 a proxy server.
459 */
460
461 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)462 ProxyCheck(struct libalias *la, struct in_addr *proxy_server_addr,
463 u_short * proxy_server_port, struct in_addr src_addr,
464 struct in_addr dst_addr, u_short dst_port, u_char ip_p)
465 {
466 struct proxy_entry *ptr;
467
468 LIBALIAS_LOCK_ASSERT(la);
469
470 ptr = la->proxyList;
471 while (ptr != NULL) {
472 u_short proxy_port;
473
474 proxy_port = ptr->proxy_port;
475 if ((dst_port == proxy_port || proxy_port == 0)
476 && ip_p == ptr->proto
477 && src_addr.s_addr != ptr->server_addr.s_addr) {
478 struct in_addr src_addr_masked;
479 struct in_addr dst_addr_masked;
480
481 src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr;
482 dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr;
483
484 if ((src_addr_masked.s_addr == ptr->src_addr.s_addr)
485 && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) {
486 if ((*proxy_server_port = ptr->server_port) == 0)
487 *proxy_server_port = dst_port;
488 *proxy_server_addr = ptr->server_addr;
489 return (ptr->proxy_type);
490 }
491 }
492 ptr = ptr->next;
493 }
494
495 return (0);
496 }
497
498 void
ProxyModify(struct libalias * la,struct alias_link * lnk,struct ip * pip,int maxpacketsize,int proxy_type)499 ProxyModify(struct libalias *la, struct alias_link *lnk,
500 struct ip *pip,
501 int maxpacketsize,
502 int proxy_type)
503 {
504
505 LIBALIAS_LOCK_ASSERT(la);
506 (void)la;
507
508 switch (proxy_type) {
509 case PROXY_TYPE_ENCODE_IPHDR:
510 ProxyEncodeIpHeader(pip, maxpacketsize);
511 break;
512
513 case PROXY_TYPE_ENCODE_TCPSTREAM:
514 ProxyEncodeTcpStream(lnk, pip, maxpacketsize);
515 break;
516 }
517 }
518
519
520 /*
521 Public API functions
522 */
523
524 int
LibAliasProxyRule(struct libalias * la,const char * cmd)525 LibAliasProxyRule(struct libalias *la, const char *cmd)
526 {
527 /*
528 * This function takes command strings of the form:
529 *
530 * server <addr>[:<port>]
531 * [port <port>]
532 * [rule n]
533 * [proto tcp|udp]
534 * [src <addr>[/n]]
535 * [dst <addr>[/n]]
536 * [type encode_tcp_stream|encode_ip_hdr|no_encode]
537 *
538 * delete <rule number>
539 *
540 * Subfields can be in arbitrary order. Port numbers and addresses
541 * must be in either numeric or symbolic form. An optional rule number
542 * is used to control the order in which rules are searched. If two
543 * rules have the same number, then search order cannot be guaranteed,
544 * and the rules should be disjoint. If no rule number is specified,
545 * then 0 is used, and group 0 rules are always checked before any
546 * others.
547 */
548 int i, n, len, ret;
549 int cmd_len;
550 int token_count;
551 int state;
552 char *token;
553 char buffer[256];
554 char str_port[sizeof(buffer)];
555 char str_server_port[sizeof(buffer)];
556 char *res = buffer;
557
558 int rule_index;
559 int proto;
560 int proxy_type;
561 int proxy_port;
562 int server_port;
563 struct in_addr server_addr;
564 struct in_addr src_addr, src_mask;
565 struct in_addr dst_addr, dst_mask;
566 struct proxy_entry *proxy_entry;
567
568 LIBALIAS_LOCK(la);
569 ret = 0;
570 /* Copy command line into a buffer */
571 cmd += strspn(cmd, " \t");
572 cmd_len = strlen(cmd);
573 if (cmd_len > (int)(sizeof(buffer) - 1)) {
574 ret = -1;
575 goto getout;
576 }
577 strcpy(buffer, cmd);
578
579 /* Convert to lower case */
580 len = strlen(buffer);
581 for (i = 0; i < len; i++)
582 buffer[i] = tolower((unsigned char)buffer[i]);
583
584 /* Set default proxy type */
585
586 /* Set up default values */
587 rule_index = 0;
588 proxy_type = PROXY_TYPE_ENCODE_NONE;
589 proto = IPPROTO_TCP;
590 proxy_port = 0;
591 server_addr.s_addr = 0;
592 server_port = 0;
593 src_addr.s_addr = 0;
594 IpMask(0, &src_mask);
595 dst_addr.s_addr = 0;
596 IpMask(0, &dst_mask);
597
598 str_port[0] = 0;
599 str_server_port[0] = 0;
600
601 /* Parse command string with state machine */
602 #define STATE_READ_KEYWORD 0
603 #define STATE_READ_TYPE 1
604 #define STATE_READ_PORT 2
605 #define STATE_READ_SERVER 3
606 #define STATE_READ_RULE 4
607 #define STATE_READ_DELETE 5
608 #define STATE_READ_PROTO 6
609 #define STATE_READ_SRC 7
610 #define STATE_READ_DST 8
611 state = STATE_READ_KEYWORD;
612 token = strsep(&res, " \t");
613 token_count = 0;
614 while (token != NULL) {
615 token_count++;
616 switch (state) {
617 case STATE_READ_KEYWORD:
618 if (strcmp(token, "type") == 0)
619 state = STATE_READ_TYPE;
620 else if (strcmp(token, "port") == 0)
621 state = STATE_READ_PORT;
622 else if (strcmp(token, "server") == 0)
623 state = STATE_READ_SERVER;
624 else if (strcmp(token, "rule") == 0)
625 state = STATE_READ_RULE;
626 else if (strcmp(token, "delete") == 0)
627 state = STATE_READ_DELETE;
628 else if (strcmp(token, "proto") == 0)
629 state = STATE_READ_PROTO;
630 else if (strcmp(token, "src") == 0)
631 state = STATE_READ_SRC;
632 else if (strcmp(token, "dst") == 0)
633 state = STATE_READ_DST;
634 else {
635 ret = -1;
636 goto getout;
637 }
638 break;
639
640 case STATE_READ_TYPE:
641 if (strcmp(token, "encode_ip_hdr") == 0)
642 proxy_type = PROXY_TYPE_ENCODE_IPHDR;
643 else if (strcmp(token, "encode_tcp_stream") == 0)
644 proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM;
645 else if (strcmp(token, "no_encode") == 0)
646 proxy_type = PROXY_TYPE_ENCODE_NONE;
647 else {
648 ret = -1;
649 goto getout;
650 }
651 state = STATE_READ_KEYWORD;
652 break;
653
654 case STATE_READ_PORT:
655 strcpy(str_port, token);
656 state = STATE_READ_KEYWORD;
657 break;
658
659 case STATE_READ_SERVER:
660 {
661 int err;
662 char *p;
663 char s[sizeof(buffer)];
664
665 p = token;
666 while (*p != ':' && *p != 0)
667 p++;
668
669 if (*p != ':') {
670 err = IpAddr(token, &server_addr);
671 if (err) {
672 ret = -1;
673 goto getout;
674 }
675 } else {
676 *p = ' ';
677
678 n = sscanf(token, "%s %s", s, str_server_port);
679 if (n != 2) {
680 ret = -1;
681 goto getout;
682 }
683
684 err = IpAddr(s, &server_addr);
685 if (err) {
686 ret = -1;
687 goto getout;
688 }
689 }
690 }
691 state = STATE_READ_KEYWORD;
692 break;
693
694 case STATE_READ_RULE:
695 n = sscanf(token, "%d", &rule_index);
696 if (n != 1 || rule_index < 0) {
697 ret = -1;
698 goto getout;
699 }
700 state = STATE_READ_KEYWORD;
701 break;
702
703 case STATE_READ_DELETE:
704 {
705 int err;
706 int rule_to_delete;
707
708 if (token_count != 2) {
709 ret = -1;
710 goto getout;
711 }
712
713 n = sscanf(token, "%d", &rule_to_delete);
714 if (n != 1) {
715 ret = -1;
716 goto getout;
717 }
718 err = RuleNumberDelete(la, rule_to_delete);
719 if (err)
720 ret = -1;
721 ret = 0;
722 goto getout;
723 }
724
725 case STATE_READ_PROTO:
726 if (strcmp(token, "tcp") == 0)
727 proto = IPPROTO_TCP;
728 else if (strcmp(token, "udp") == 0)
729 proto = IPPROTO_UDP;
730 else {
731 ret = -1;
732 goto getout;
733 }
734 state = STATE_READ_KEYWORD;
735 break;
736
737 case STATE_READ_SRC:
738 case STATE_READ_DST:
739 {
740 int err;
741 char *p;
742 struct in_addr mask;
743 struct in_addr addr;
744
745 p = token;
746 while (*p != '/' && *p != 0)
747 p++;
748
749 if (*p != '/') {
750 IpMask(32, &mask);
751 err = IpAddr(token, &addr);
752 if (err) {
753 ret = -1;
754 goto getout;
755 }
756 } else {
757 int nbits;
758 char s[sizeof(buffer)];
759
760 *p = ' ';
761 n = sscanf(token, "%s %d", s, &nbits);
762 if (n != 2) {
763 ret = -1;
764 goto getout;
765 }
766
767 err = IpAddr(s, &addr);
768 if (err) {
769 ret = -1;
770 goto getout;
771 }
772
773 err = IpMask(nbits, &mask);
774 if (err) {
775 ret = -1;
776 goto getout;
777 }
778 }
779
780 if (state == STATE_READ_SRC) {
781 src_addr = addr;
782 src_mask = mask;
783 } else {
784 dst_addr = addr;
785 dst_mask = mask;
786 }
787 }
788 state = STATE_READ_KEYWORD;
789 break;
790
791 default:
792 ret = -1;
793 goto getout;
794 break;
795 }
796
797 do {
798 token = strsep(&res, " \t");
799 } while (token != NULL && !*token);
800 }
801 #undef STATE_READ_KEYWORD
802 #undef STATE_READ_TYPE
803 #undef STATE_READ_PORT
804 #undef STATE_READ_SERVER
805 #undef STATE_READ_RULE
806 #undef STATE_READ_DELETE
807 #undef STATE_READ_PROTO
808 #undef STATE_READ_SRC
809 #undef STATE_READ_DST
810
811 /* Convert port strings to numbers. This needs to be done after
812 the string is parsed, because the prototype might not be designated
813 before the ports (which might be symbolic entries in /etc/services) */
814
815 if (strlen(str_port) != 0) {
816 int err;
817
818 err = IpPort(str_port, proto, &proxy_port);
819 if (err) {
820 ret = -1;
821 goto getout;
822 }
823 } else {
824 proxy_port = 0;
825 }
826
827 if (strlen(str_server_port) != 0) {
828 int err;
829
830 err = IpPort(str_server_port, proto, &server_port);
831 if (err) {
832 ret = -1;
833 goto getout;
834 }
835 } else {
836 server_port = 0;
837 }
838
839 /* Check that at least the server address has been defined */
840 if (server_addr.s_addr == 0) {
841 ret = -1;
842 goto getout;
843 }
844
845 /* Add to linked list */
846 proxy_entry = malloc(sizeof(struct proxy_entry));
847 if (proxy_entry == NULL) {
848 ret = -1;
849 goto getout;
850 }
851
852 proxy_entry->proxy_type = proxy_type;
853 proxy_entry->rule_index = rule_index;
854 proxy_entry->proto = proto;
855 proxy_entry->proxy_port = htons(proxy_port);
856 proxy_entry->server_port = htons(server_port);
857 proxy_entry->server_addr = server_addr;
858 proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr;
859 proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr;
860 proxy_entry->src_mask = src_mask;
861 proxy_entry->dst_mask = dst_mask;
862
863 RuleAdd(la, proxy_entry);
864
865 getout:
866 LIBALIAS_UNLOCK(la);
867 return (ret);
868 }
869