1274955Ssvnmir/*- 2274955Ssvnmir * Copyright (c) 2001 Charles Mott <cm@linktel.net> 3353358Sdim * All rights reserved. 4353358Sdim * 5353358Sdim * Redistribution and use in source and binary forms, with or without 6274955Ssvnmir * modification, are permitted provided that the following conditions 7274955Ssvnmir * are met: 8274955Ssvnmir * 1. Redistributions of source code must retain the above copyright 9274955Ssvnmir * notice, this list of conditions and the following disclaimer. 10274955Ssvnmir * 2. Redistributions in binary form must reproduce the above copyright 11274955Ssvnmir * notice, this list of conditions and the following disclaimer in the 12274955Ssvnmir * documentation and/or other materials provided with the distribution. 13274955Ssvnmir * 14274955Ssvnmir * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15321369Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16274955Ssvnmir * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17274955Ssvnmir * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18274955Ssvnmir * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19274955Ssvnmir * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20274955Ssvnmir * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21274955Ssvnmir * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22274955Ssvnmir * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23274955Ssvnmir * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24274955Ssvnmir * SUCH DAMAGE. 25274955Ssvnmir */ 26274955Ssvnmir 27309124Sdim#include <sys/cdefs.h> 28327952Sdim__FBSDID("$FreeBSD: releng/10.3/sys/netinet/libalias/alias_proxy.c 241648 2012-10-17 20:23:07Z emaste $"); 29363496Sdim 30363496Sdim/* file: alias_proxy.c 31274955Ssvnmir 32274955Ssvnmir This file encapsulates special operations related to transparent 33274955Ssvnmir proxy redirection. This is where packets with a particular destination, 34274955Ssvnmir usually tcp port 80, are redirected to a proxy server. 35274955Ssvnmir 36274955Ssvnmir When packets are proxied, the destination address and port are 37274955Ssvnmir modified. In certain cases, it is necessary to somehow encode 38274955Ssvnmir the original address/port info into the packet. Two methods are 39274955Ssvnmir presently supported: addition of a [DEST addr port] string at the 40274955Ssvnmir beginning of a tcp stream, or inclusion of an optional field 41274955Ssvnmir in the IP header. 42274955Ssvnmir 43274955Ssvnmir There is one public API function: 44274955Ssvnmir 45274955Ssvnmir PacketAliasProxyRule() -- Adds and deletes proxy 46274955Ssvnmir rules. 47274955Ssvnmir 48274955Ssvnmir Rules are stored in a linear linked list, so lookup efficiency 49274955Ssvnmir won't be too good for large lists. 50274955Ssvnmir 51274955Ssvnmir 52274955Ssvnmir Initial development: April, 1998 (cjm) 53274955Ssvnmir*/ 54274955Ssvnmir 55274955Ssvnmir 56274955Ssvnmir/* System includes */ 57274955Ssvnmir#ifdef _KERNEL 58274955Ssvnmir#include <sys/param.h> 59274955Ssvnmir#include <sys/ctype.h> 60274955Ssvnmir#include <sys/libkern.h> 61274955Ssvnmir#include <sys/limits.h> 62274955Ssvnmir#else 63274955Ssvnmir#include <sys/types.h> 64274955Ssvnmir#include <ctype.h> 65274955Ssvnmir#include <stdio.h> 66274955Ssvnmir#include <stdlib.h> 67274955Ssvnmir#include <netdb.h> 68274955Ssvnmir#include <string.h> 69274955Ssvnmir#endif 70274955Ssvnmir 71274955Ssvnmir#include <netinet/tcp.h> 72274955Ssvnmir 73274955Ssvnmir#ifdef _KERNEL 74274955Ssvnmir#include <netinet/libalias/alias.h> 75274955Ssvnmir#include <netinet/libalias/alias_local.h> 76274955Ssvnmir#include <netinet/libalias/alias_mod.h> 77274955Ssvnmir#else 78274955Ssvnmir#include <arpa/inet.h> 79274955Ssvnmir#include "alias.h" /* Public API functions for libalias */ 80274955Ssvnmir#include "alias_local.h" /* Functions used by alias*.c */ 81274955Ssvnmir#endif 82274955Ssvnmir 83274955Ssvnmir/* 84274955Ssvnmir Data structures 85274955Ssvnmir */ 86274955Ssvnmir 87274955Ssvnmir/* 88274955Ssvnmir * A linked list of arbitrary length, based on struct proxy_entry is 89274955Ssvnmir * used to store proxy rules. 90274955Ssvnmir */ 91274955Ssvnmirstruct proxy_entry { 92274955Ssvnmir struct libalias *la; 93274955Ssvnmir#define PROXY_TYPE_ENCODE_NONE 1 94274955Ssvnmir#define PROXY_TYPE_ENCODE_TCPSTREAM 2 95274955Ssvnmir#define PROXY_TYPE_ENCODE_IPHDR 3 96274955Ssvnmir int rule_index; 97274955Ssvnmir int proxy_type; 98274955Ssvnmir u_char proto; 99274955Ssvnmir u_short proxy_port; 100274955Ssvnmir u_short server_port; 101274955Ssvnmir 102274955Ssvnmir struct in_addr server_addr; 103274955Ssvnmir 104274955Ssvnmir struct in_addr src_addr; 105274955Ssvnmir struct in_addr src_mask; 106274955Ssvnmir 107274955Ssvnmir struct in_addr dst_addr; 108274955Ssvnmir struct in_addr dst_mask; 109274955Ssvnmir 110274955Ssvnmir struct proxy_entry *next; 111274955Ssvnmir struct proxy_entry *last; 112274955Ssvnmir}; 113274955Ssvnmir 114309124Sdim 115309124Sdim 116274955Ssvnmir/* 117274955Ssvnmir File scope variables 118274955Ssvnmir*/ 119274955Ssvnmir 120274955Ssvnmir 121274955Ssvnmir 122274955Ssvnmir/* Local (static) functions: 123274955Ssvnmir 124274955Ssvnmir IpMask() -- Utility function for creating IP 125274955Ssvnmir masks from integer (1-32) specification. 126274955Ssvnmir IpAddr() -- Utility function for converting string 127274955Ssvnmir to IP address 128274955Ssvnmir IpPort() -- Utility function for converting string 129274955Ssvnmir to port number 130274955Ssvnmir RuleAdd() -- Adds an element to the rule list. 131274955Ssvnmir RuleDelete() -- Removes an element from the rule list. 132274955Ssvnmir RuleNumberDelete() -- Removes all elements from the rule list 133274955Ssvnmir having a certain rule number. 134274955Ssvnmir ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning 135274955Ssvnmir of a TCP stream. 136274955Ssvnmir ProxyEncodeIpHeader() -- Adds an IP option indicating the true 137274955Ssvnmir destination of a proxied IP packet 138274955Ssvnmir*/ 139274955Ssvnmir 140274955Ssvnmirstatic int IpMask(int, struct in_addr *); 141274955Ssvnmirstatic int IpAddr(char *, struct in_addr *); 142274955Ssvnmirstatic int IpPort(char *, int, int *); 143274955Ssvnmirstatic void RuleAdd(struct libalias *la, struct proxy_entry *); 144274955Ssvnmirstatic void RuleDelete(struct proxy_entry *); 145274955Ssvnmirstatic int RuleNumberDelete(struct libalias *la, int); 146274955Ssvnmirstatic void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 147274955Ssvnmirstatic void ProxyEncodeIpHeader(struct ip *, int); 148274955Ssvnmir 149274955Ssvnmirstatic int 150274955SsvnmirIpMask(int nbits, struct in_addr *mask) 151274955Ssvnmir{ 152274955Ssvnmir int i; 153274955Ssvnmir u_int imask; 154274955Ssvnmir 155274955Ssvnmir if (nbits < 0 || nbits > 32) 156274955Ssvnmir return (-1); 157274955Ssvnmir 158274955Ssvnmir imask = 0; 159274955Ssvnmir for (i = 0; i < nbits; i++) 160274955Ssvnmir imask = (imask >> 1) + 0x80000000; 161274955Ssvnmir mask->s_addr = htonl(imask); 162274955Ssvnmir 163274955Ssvnmir return (0); 164274955Ssvnmir} 165274955Ssvnmir 166274955Ssvnmirstatic int 167274955SsvnmirIpAddr(char *s, struct in_addr *addr) 168274955Ssvnmir{ 169274955Ssvnmir if (inet_aton(s, addr) == 0) 170274955Ssvnmir return (-1); 171274955Ssvnmir else 172274955Ssvnmir return (0); 173274955Ssvnmir} 174274955Ssvnmir 175274955Ssvnmirstatic int 176274955SsvnmirIpPort(char *s, int proto, int *port) 177274955Ssvnmir{ 178274955Ssvnmir int n; 179274955Ssvnmir 180274955Ssvnmir n = sscanf(s, "%d", port); 181274955Ssvnmir if (n != 1) 182274955Ssvnmir#ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */ 183274955Ssvnmir { 184274955Ssvnmir struct servent *se; 185274955Ssvnmir 186274955Ssvnmir if (proto == IPPROTO_TCP) 187274955Ssvnmir se = getservbyname(s, "tcp"); 188274955Ssvnmir else if (proto == IPPROTO_UDP) 189274955Ssvnmir se = getservbyname(s, "udp"); 190274955Ssvnmir else 191274955Ssvnmir return (-1); 192274955Ssvnmir 193274955Ssvnmir if (se == NULL) 194274955Ssvnmir return (-1); 195274955Ssvnmir 196274955Ssvnmir *port = (u_int) ntohs(se->s_port); 197274955Ssvnmir } 198274955Ssvnmir#else 199274955Ssvnmir return (-1); 200274955Ssvnmir#endif 201274955Ssvnmir return (0); 202274955Ssvnmir} 203274955Ssvnmir 204274955Ssvnmirvoid 205274955SsvnmirRuleAdd(struct libalias *la, struct proxy_entry *entry) 206274955Ssvnmir{ 207274955Ssvnmir int rule_index; 208274955Ssvnmir struct proxy_entry *ptr; 209274955Ssvnmir struct proxy_entry *ptr_last; 210274955Ssvnmir 211274955Ssvnmir LIBALIAS_LOCK_ASSERT(la); 212274955Ssvnmir 213274955Ssvnmir entry->la = la; 214274955Ssvnmir if (la->proxyList == NULL) { 215274955Ssvnmir la->proxyList = entry; 216274955Ssvnmir entry->last = NULL; 217274955Ssvnmir entry->next = NULL; 218274955Ssvnmir return; 219274955Ssvnmir } 220274955Ssvnmir 221274955Ssvnmir rule_index = entry->rule_index; 222274955Ssvnmir ptr = la->proxyList; 223274955Ssvnmir ptr_last = NULL; 224274955Ssvnmir while (ptr != NULL) { 225341825Sdim if (ptr->rule_index >= rule_index) { 226341825Sdim if (ptr_last == NULL) { 227341825Sdim entry->next = la->proxyList; 228341825Sdim entry->last = NULL; 229274955Ssvnmir la->proxyList->last = entry; 230274955Ssvnmir la->proxyList = entry; 231274955Ssvnmir return; 232274955Ssvnmir } 233341825Sdim ptr_last->next = entry; 234274955Ssvnmir ptr->last = entry; 235274955Ssvnmir entry->last = ptr->last; 236274955Ssvnmir entry->next = ptr; 237341825Sdim return; 238274955Ssvnmir } 239274955Ssvnmir ptr_last = ptr; 240274955Ssvnmir ptr = ptr->next; 241274955Ssvnmir } 242274955Ssvnmir 243274955Ssvnmir ptr_last->next = entry; 244274955Ssvnmir entry->last = ptr_last; 245274955Ssvnmir entry->next = NULL; 246274955Ssvnmir} 247274955Ssvnmir 248274955Ssvnmirstatic void 249274955SsvnmirRuleDelete(struct proxy_entry *entry) 250274955Ssvnmir{ 251274955Ssvnmir struct libalias *la; 252274955Ssvnmir 253274955Ssvnmir la = entry->la; 254274955Ssvnmir LIBALIAS_LOCK_ASSERT(la); 255274955Ssvnmir if (entry->last != NULL) 256274955Ssvnmir entry->last->next = entry->next; 257274955Ssvnmir else 258274955Ssvnmir la->proxyList = entry->next; 259274955Ssvnmir 260274955Ssvnmir if (entry->next != NULL) 261274955Ssvnmir entry->next->last = entry->last; 262274955Ssvnmir 263274955Ssvnmir free(entry); 264274955Ssvnmir} 265274955Ssvnmir 266274955Ssvnmirstatic int 267274955SsvnmirRuleNumberDelete(struct libalias *la, int rule_index) 268274955Ssvnmir{ 269274955Ssvnmir int err; 270274955Ssvnmir struct proxy_entry *ptr; 271274955Ssvnmir 272274955Ssvnmir LIBALIAS_LOCK_ASSERT(la); 273274955Ssvnmir err = -1; 274274955Ssvnmir ptr = la->proxyList; 275274955Ssvnmir while (ptr != NULL) { 276274955Ssvnmir struct proxy_entry *ptr_next; 277274955Ssvnmir 278274955Ssvnmir ptr_next = ptr->next; 279274955Ssvnmir if (ptr->rule_index == rule_index) { 280274955Ssvnmir err = 0; 281274955Ssvnmir RuleDelete(ptr); 282274955Ssvnmir } 283274955Ssvnmir ptr = ptr_next; 284274955Ssvnmir } 285274955Ssvnmir 286274955Ssvnmir return (err); 287274955Ssvnmir} 288274955Ssvnmir 289274955Ssvnmirstatic void 290274955SsvnmirProxyEncodeTcpStream(struct alias_link *lnk, 291274955Ssvnmir struct ip *pip, 292274955Ssvnmir int maxpacketsize) 293274955Ssvnmir{ 294274955Ssvnmir int slen; 295274955Ssvnmir 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 380static void 381ProxyEncodeIpHeader(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 461int 462ProxyCheck(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 498void 499ProxyModify(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 524int 525LibAliasProxyRule(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 865getout: 866 LIBALIAS_UNLOCK(la); 867 return (ret); 868} 869