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