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