1f987e1bdSBrian Somers /*- 2e83aaae3SBrian Somers * Copyright (c) 2001 Charles Mott <cm@linktel.net> 3f987e1bdSBrian Somers * All rights reserved. 4f987e1bdSBrian Somers * 5f987e1bdSBrian Somers * Redistribution and use in source and binary forms, with or without 6f987e1bdSBrian Somers * modification, are permitted provided that the following conditions 7f987e1bdSBrian Somers * are met: 8f987e1bdSBrian Somers * 1. Redistributions of source code must retain the above copyright 9f987e1bdSBrian Somers * notice, this list of conditions and the following disclaimer. 10f987e1bdSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 11f987e1bdSBrian Somers * notice, this list of conditions and the following disclaimer in the 12f987e1bdSBrian Somers * documentation and/or other materials provided with the distribution. 13f987e1bdSBrian Somers * 14f987e1bdSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15f987e1bdSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f987e1bdSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f987e1bdSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f987e1bdSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f987e1bdSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f987e1bdSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f987e1bdSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f987e1bdSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f987e1bdSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f987e1bdSBrian Somers * SUCH DAMAGE. 25f987e1bdSBrian Somers */ 26f987e1bdSBrian Somers 27e2505aa6SMatthew Dillon #include <sys/cdefs.h> 28e2505aa6SMatthew Dillon __FBSDID("$FreeBSD$"); 29e2505aa6SMatthew Dillon 307d96f4efSBrian Somers /* file: alias_proxy.c 317d96f4efSBrian Somers 327d96f4efSBrian Somers This file encapsulates special operations related to transparent 337d96f4efSBrian Somers proxy redirection. This is where packets with a particular destination, 347d96f4efSBrian Somers usually tcp port 80, are redirected to a proxy server. 357d96f4efSBrian Somers 367d96f4efSBrian Somers When packets are proxied, the destination address and port are 377d96f4efSBrian Somers modified. In certain cases, it is necessary to somehow encode 387d96f4efSBrian Somers the original address/port info into the packet. Two methods are 397d96f4efSBrian Somers presently supported: addition of a [DEST addr port] string at the 409d5abbddSJens Schweikhardt beginning of a tcp stream, or inclusion of an optional field 417d96f4efSBrian Somers in the IP header. 427d96f4efSBrian Somers 437d96f4efSBrian Somers There is one public API function: 447d96f4efSBrian Somers 457d96f4efSBrian Somers PacketAliasProxyRule() -- Adds and deletes proxy 467d96f4efSBrian Somers rules. 477d96f4efSBrian Somers 487d96f4efSBrian Somers Rules are stored in a linear linked list, so lookup efficiency 497d96f4efSBrian Somers won't be too good for large lists. 507d96f4efSBrian Somers 517d96f4efSBrian Somers 527d96f4efSBrian Somers Initial development: April, 1998 (cjm) 537d96f4efSBrian Somers */ 547d96f4efSBrian Somers 557d96f4efSBrian Somers 567d96f4efSBrian Somers /* System includes */ 57c649a2e0SGleb Smirnoff #ifdef _KERNEL 58c649a2e0SGleb Smirnoff #include <sys/param.h> 59c649a2e0SGleb Smirnoff #include <sys/ctype.h> 60c649a2e0SGleb Smirnoff #include <sys/libkern.h> 61c649a2e0SGleb Smirnoff #include <sys/limits.h> 62c649a2e0SGleb Smirnoff #else 63c649a2e0SGleb Smirnoff #include <sys/types.h> 647d96f4efSBrian Somers #include <ctype.h> 657d96f4efSBrian Somers #include <stdio.h> 667d96f4efSBrian Somers #include <stdlib.h> 677d96f4efSBrian Somers #include <netdb.h> 68be4f3cd0SPaolo Pisati #include <string.h> 69c649a2e0SGleb Smirnoff #endif 707d96f4efSBrian Somers 717d96f4efSBrian Somers #include <netinet/tcp.h> 727d96f4efSBrian Somers 73c649a2e0SGleb Smirnoff #ifdef _KERNEL 74c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h> 7575bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h> 76be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h> 77c649a2e0SGleb Smirnoff #else 78be4f3cd0SPaolo Pisati #include <arpa/inet.h> 797d96f4efSBrian Somers #include "alias.h" /* Public API functions for libalias */ 8075bc2620SGleb Smirnoff #include "alias_local.h" /* Functions used by alias*.c */ 81c649a2e0SGleb Smirnoff #endif 827d96f4efSBrian Somers 837d96f4efSBrian Somers /* 847d96f4efSBrian Somers Data structures 857d96f4efSBrian Somers */ 867d96f4efSBrian Somers 877d96f4efSBrian Somers /* 887d96f4efSBrian Somers * A linked list of arbitrary length, based on struct proxy_entry is 897d96f4efSBrian Somers * used to store proxy rules. 907d96f4efSBrian Somers */ 91f0f93429SDag-Erling Smørgrav struct proxy_entry { 925e289f9eSPoul-Henning Kamp struct libalias *la; 937d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_NONE 1 947d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_TCPSTREAM 2 957d96f4efSBrian Somers #define PROXY_TYPE_ENCODE_IPHDR 3 967d96f4efSBrian Somers int rule_index; 977d96f4efSBrian Somers int proxy_type; 987d96f4efSBrian Somers u_char proto; 997d96f4efSBrian Somers u_short proxy_port; 1007d96f4efSBrian Somers u_short server_port; 1017d96f4efSBrian Somers 1027d96f4efSBrian Somers struct in_addr server_addr; 1037d96f4efSBrian Somers 1047d96f4efSBrian Somers struct in_addr src_addr; 1057d96f4efSBrian Somers struct in_addr src_mask; 1067d96f4efSBrian Somers 1077d96f4efSBrian Somers struct in_addr dst_addr; 1087d96f4efSBrian Somers struct in_addr dst_mask; 1097d96f4efSBrian Somers 1107d96f4efSBrian Somers struct proxy_entry *next; 1117d96f4efSBrian Somers struct proxy_entry *last; 1127d96f4efSBrian Somers }; 1137d96f4efSBrian Somers 1147d96f4efSBrian Somers 1157d96f4efSBrian Somers 1167d96f4efSBrian Somers /* 1177d96f4efSBrian Somers File scope variables 1187d96f4efSBrian Somers */ 1197d96f4efSBrian Somers 1207d96f4efSBrian Somers 1217d96f4efSBrian Somers 1227d96f4efSBrian Somers /* Local (static) functions: 1237d96f4efSBrian Somers 1247d96f4efSBrian Somers IpMask() -- Utility function for creating IP 1257d96f4efSBrian Somers masks from integer (1-32) specification. 1267d96f4efSBrian Somers IpAddr() -- Utility function for converting string 1277d96f4efSBrian Somers to IP address 1287d96f4efSBrian Somers IpPort() -- Utility function for converting string 1297d96f4efSBrian Somers to port number 1307d96f4efSBrian Somers RuleAdd() -- Adds an element to the rule list. 1317d96f4efSBrian Somers RuleDelete() -- Removes an element from the rule list. 1327d96f4efSBrian Somers RuleNumberDelete() -- Removes all elements from the rule list 1337d96f4efSBrian Somers having a certain rule number. 1347d96f4efSBrian Somers ProxyEncodeTcpStream() -- Adds [DEST x.x.x.x xxxx] to the beginning 1357d96f4efSBrian Somers of a TCP stream. 1367d96f4efSBrian Somers ProxyEncodeIpHeader() -- Adds an IP option indicating the true 1377d96f4efSBrian Somers destination of a proxied IP packet 1387d96f4efSBrian Somers */ 1397d96f4efSBrian Somers 140e9d5db28SGleb Smirnoff #ifdef _KERNEL /* XXX: can it be moved to libkern? */ 141e9d5db28SGleb Smirnoff static int inet_aton(const char *cp, struct in_addr *addr); 142e9d5db28SGleb Smirnoff #endif 1437d96f4efSBrian Somers static int IpMask(int, struct in_addr *); 1447d96f4efSBrian Somers static int IpAddr(char *, struct in_addr *); 1457d96f4efSBrian Somers static int IpPort(char *, int, int *); 1465e289f9eSPoul-Henning Kamp static void RuleAdd(struct libalias *la, struct proxy_entry *); 1477d96f4efSBrian Somers static void RuleDelete(struct proxy_entry *); 1485e289f9eSPoul-Henning Kamp static int RuleNumberDelete(struct libalias *la, int); 1497d96f4efSBrian Somers static void ProxyEncodeTcpStream(struct alias_link *, struct ip *, int); 1507d96f4efSBrian Somers static void ProxyEncodeIpHeader(struct ip *, int); 1517d96f4efSBrian Somers 152e9d5db28SGleb Smirnoff #ifdef _KERNEL 153e9d5db28SGleb Smirnoff static int 154e9d5db28SGleb Smirnoff inet_aton(cp, addr) 155e9d5db28SGleb Smirnoff const char *cp; 156e9d5db28SGleb Smirnoff struct in_addr *addr; 157e9d5db28SGleb Smirnoff { 158e9d5db28SGleb Smirnoff u_long parts[4]; 159e9d5db28SGleb Smirnoff in_addr_t val; 160e9d5db28SGleb Smirnoff const char *c; 161e9d5db28SGleb Smirnoff char *endptr; 162e9d5db28SGleb Smirnoff int gotend, n; 163e9d5db28SGleb Smirnoff 164e9d5db28SGleb Smirnoff c = (const char *)cp; 165e9d5db28SGleb Smirnoff n = 0; 166e9d5db28SGleb Smirnoff /* 167e9d5db28SGleb Smirnoff * Run through the string, grabbing numbers until 168e9d5db28SGleb Smirnoff * the end of the string, or some error 169e9d5db28SGleb Smirnoff */ 170e9d5db28SGleb Smirnoff gotend = 0; 171e9d5db28SGleb Smirnoff while (!gotend) { 172cbfbc555SGleb Smirnoff unsigned long l; 173e9d5db28SGleb Smirnoff 174cbfbc555SGleb Smirnoff l = strtoul(c, &endptr, 0); 175cbfbc555SGleb Smirnoff 176cbfbc555SGleb Smirnoff if (l == ULONG_MAX || l == 0) 177e9d5db28SGleb Smirnoff return (0); 178e9d5db28SGleb Smirnoff 179cbfbc555SGleb Smirnoff val = (in_addr_t)l; 180e9d5db28SGleb Smirnoff /* 181e9d5db28SGleb Smirnoff * If the whole string is invalid, endptr will equal 182e9d5db28SGleb Smirnoff * c.. this way we can make sure someone hasn't 183e9d5db28SGleb Smirnoff * gone '.12' or something which would get past 184e9d5db28SGleb Smirnoff * the next check. 185e9d5db28SGleb Smirnoff */ 186e9d5db28SGleb Smirnoff if (endptr == c) 187e9d5db28SGleb Smirnoff return (0); 188e9d5db28SGleb Smirnoff parts[n] = val; 189e9d5db28SGleb Smirnoff c = endptr; 190e9d5db28SGleb Smirnoff 191e9d5db28SGleb Smirnoff /* Check the next character past the previous number's end */ 192e9d5db28SGleb Smirnoff switch (*c) { 193e9d5db28SGleb Smirnoff case '.' : 194e9d5db28SGleb Smirnoff /* Make sure we only do 3 dots .. */ 195e9d5db28SGleb Smirnoff if (n == 3) /* Whoops. Quit. */ 196e9d5db28SGleb Smirnoff return (0); 197e9d5db28SGleb Smirnoff n++; 198e9d5db28SGleb Smirnoff c++; 199e9d5db28SGleb Smirnoff break; 200e9d5db28SGleb Smirnoff 201e9d5db28SGleb Smirnoff case '\0': 202e9d5db28SGleb Smirnoff gotend = 1; 203e9d5db28SGleb Smirnoff break; 204e9d5db28SGleb Smirnoff 205e9d5db28SGleb Smirnoff default: 206e9d5db28SGleb Smirnoff if (isspace((unsigned char)*c)) { 207e9d5db28SGleb Smirnoff gotend = 1; 208e9d5db28SGleb Smirnoff break; 209e9d5db28SGleb Smirnoff } else 210e9d5db28SGleb Smirnoff return (0); /* Invalid character, so fail */ 211e9d5db28SGleb Smirnoff } 212e9d5db28SGleb Smirnoff 213e9d5db28SGleb Smirnoff } 214e9d5db28SGleb Smirnoff 215e9d5db28SGleb Smirnoff /* 216e9d5db28SGleb Smirnoff * Concoct the address according to 217e9d5db28SGleb Smirnoff * the number of parts specified. 218e9d5db28SGleb Smirnoff */ 219e9d5db28SGleb Smirnoff 220e9d5db28SGleb Smirnoff switch (n) { 221e9d5db28SGleb Smirnoff case 0: /* a -- 32 bits */ 222e9d5db28SGleb Smirnoff /* 223e9d5db28SGleb Smirnoff * Nothing is necessary here. Overflow checking was 224e9d5db28SGleb Smirnoff * already done in strtoul(). 225e9d5db28SGleb Smirnoff */ 226e9d5db28SGleb Smirnoff break; 227e9d5db28SGleb Smirnoff case 1: /* a.b -- 8.24 bits */ 228e9d5db28SGleb Smirnoff if (val > 0xffffff || parts[0] > 0xff) 229e9d5db28SGleb Smirnoff return (0); 230e9d5db28SGleb Smirnoff val |= parts[0] << 24; 231e9d5db28SGleb Smirnoff break; 232e9d5db28SGleb Smirnoff 233e9d5db28SGleb Smirnoff case 2: /* a.b.c -- 8.8.16 bits */ 234e9d5db28SGleb Smirnoff if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) 235e9d5db28SGleb Smirnoff return (0); 236e9d5db28SGleb Smirnoff val |= (parts[0] << 24) | (parts[1] << 16); 237e9d5db28SGleb Smirnoff break; 238e9d5db28SGleb Smirnoff 239e9d5db28SGleb Smirnoff case 3: /* a.b.c.d -- 8.8.8.8 bits */ 240e9d5db28SGleb Smirnoff if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || 241e9d5db28SGleb Smirnoff parts[2] > 0xff) 242e9d5db28SGleb Smirnoff return (0); 243e9d5db28SGleb Smirnoff val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); 244e9d5db28SGleb Smirnoff break; 245e9d5db28SGleb Smirnoff } 246e9d5db28SGleb Smirnoff 247e9d5db28SGleb Smirnoff if (addr != NULL) 248e9d5db28SGleb Smirnoff addr->s_addr = htonl(val); 249e9d5db28SGleb Smirnoff return (1); 250e9d5db28SGleb Smirnoff } 251e9d5db28SGleb Smirnoff #endif 252e9d5db28SGleb Smirnoff 2537d96f4efSBrian Somers static int 2547d96f4efSBrian Somers IpMask(int nbits, struct in_addr *mask) 2557d96f4efSBrian Somers { 2567d96f4efSBrian Somers int i; 2577d96f4efSBrian Somers u_int imask; 2587d96f4efSBrian Somers 2597d96f4efSBrian Somers if (nbits < 0 || nbits > 32) 260ffcb611aSDag-Erling Smørgrav return (-1); 2617d96f4efSBrian Somers 2627d96f4efSBrian Somers imask = 0; 2637d96f4efSBrian Somers for (i = 0; i < nbits; i++) 2647d96f4efSBrian Somers imask = (imask >> 1) + 0x80000000; 2657d96f4efSBrian Somers mask->s_addr = htonl(imask); 2667d96f4efSBrian Somers 267ffcb611aSDag-Erling Smørgrav return (0); 2687d96f4efSBrian Somers } 2697d96f4efSBrian Somers 2707d96f4efSBrian Somers static int 2717d96f4efSBrian Somers IpAddr(char *s, struct in_addr *addr) 2727d96f4efSBrian Somers { 2737d96f4efSBrian Somers if (inet_aton(s, addr) == 0) 274ffcb611aSDag-Erling Smørgrav return (-1); 2757d96f4efSBrian Somers else 276ffcb611aSDag-Erling Smørgrav return (0); 2777d96f4efSBrian Somers } 2787d96f4efSBrian Somers 2797d96f4efSBrian Somers static int 2807d96f4efSBrian Somers IpPort(char *s, int proto, int *port) 2817d96f4efSBrian Somers { 2827d96f4efSBrian Somers int n; 2837d96f4efSBrian Somers 2847d96f4efSBrian Somers n = sscanf(s, "%d", port); 285e9d5db28SGleb Smirnoff if (n != 1) 286e9d5db28SGleb Smirnoff #ifndef _KERNEL /* XXX: we accept only numeric ports in kernel */ 287e9d5db28SGleb Smirnoff { 2887d96f4efSBrian Somers struct servent *se; 2897d96f4efSBrian Somers 2907d96f4efSBrian Somers if (proto == IPPROTO_TCP) 2917d96f4efSBrian Somers se = getservbyname(s, "tcp"); 2927d96f4efSBrian Somers else if (proto == IPPROTO_UDP) 2937d96f4efSBrian Somers se = getservbyname(s, "udp"); 2947d96f4efSBrian Somers else 295ffcb611aSDag-Erling Smørgrav return (-1); 2967d96f4efSBrian Somers 2977d96f4efSBrian Somers if (se == NULL) 298ffcb611aSDag-Erling Smørgrav return (-1); 2997d96f4efSBrian Somers 3007d96f4efSBrian Somers *port = (u_int) ntohs(se->s_port); 3017d96f4efSBrian Somers } 302e9d5db28SGleb Smirnoff #else 303e9d5db28SGleb Smirnoff return (-1); 304e9d5db28SGleb Smirnoff #endif 305ffcb611aSDag-Erling Smørgrav return (0); 3067d96f4efSBrian Somers } 3077d96f4efSBrian Somers 3087d96f4efSBrian Somers void 3095e289f9eSPoul-Henning Kamp RuleAdd(struct libalias *la, struct proxy_entry *entry) 3107d96f4efSBrian Somers { 3117d96f4efSBrian Somers int rule_index; 3127d96f4efSBrian Somers struct proxy_entry *ptr; 3137d96f4efSBrian Somers struct proxy_entry *ptr_last; 3147d96f4efSBrian Somers 315ccd57eeaSPaolo Pisati LIBALIAS_LOCK_ASSERT(la); 316ccd57eeaSPaolo Pisati 317f0f93429SDag-Erling Smørgrav if (la->proxyList == NULL) { 3185e289f9eSPoul-Henning Kamp la->proxyList = entry; 3197d96f4efSBrian Somers entry->last = NULL; 3207d96f4efSBrian Somers entry->next = NULL; 3217d96f4efSBrian Somers return; 3227d96f4efSBrian Somers } 3235e289f9eSPoul-Henning Kamp entry->la = la; 3247d96f4efSBrian Somers 3257d96f4efSBrian Somers rule_index = entry->rule_index; 3265e289f9eSPoul-Henning Kamp ptr = la->proxyList; 3277d96f4efSBrian Somers ptr_last = NULL; 328f0f93429SDag-Erling Smørgrav while (ptr != NULL) { 329f0f93429SDag-Erling Smørgrav if (ptr->rule_index >= rule_index) { 330f0f93429SDag-Erling Smørgrav if (ptr_last == NULL) { 3315e289f9eSPoul-Henning Kamp entry->next = la->proxyList; 3327d96f4efSBrian Somers entry->last = NULL; 3335e289f9eSPoul-Henning Kamp la->proxyList->last = entry; 3345e289f9eSPoul-Henning Kamp la->proxyList = entry; 3357d96f4efSBrian Somers return; 3367d96f4efSBrian Somers } 3377d96f4efSBrian Somers ptr_last->next = entry; 3387d96f4efSBrian Somers ptr->last = entry; 3397d96f4efSBrian Somers entry->last = ptr->last; 3407d96f4efSBrian Somers entry->next = ptr; 3417d96f4efSBrian Somers return; 3427d96f4efSBrian Somers } 3437d96f4efSBrian Somers ptr_last = ptr; 3447d96f4efSBrian Somers ptr = ptr->next; 3457d96f4efSBrian Somers } 3467d96f4efSBrian Somers 3477d96f4efSBrian Somers ptr_last->next = entry; 3487d96f4efSBrian Somers entry->last = ptr_last; 3497d96f4efSBrian Somers entry->next = NULL; 3507d96f4efSBrian Somers } 3517d96f4efSBrian Somers 3527d96f4efSBrian Somers static void 3537d96f4efSBrian Somers RuleDelete(struct proxy_entry *entry) 3547d96f4efSBrian Somers { 3555e289f9eSPoul-Henning Kamp struct libalias *la; 3565e289f9eSPoul-Henning Kamp 3575e289f9eSPoul-Henning Kamp la = entry->la; 358ccd57eeaSPaolo Pisati LIBALIAS_LOCK_ASSERT(la); 3597d96f4efSBrian Somers if (entry->last != NULL) 3607d96f4efSBrian Somers entry->last->next = entry->next; 3617d96f4efSBrian Somers else 3625e289f9eSPoul-Henning Kamp la->proxyList = entry->next; 3637d96f4efSBrian Somers 3647d96f4efSBrian Somers if (entry->next != NULL) 3657d96f4efSBrian Somers entry->next->last = entry->last; 3667d96f4efSBrian Somers 3677d96f4efSBrian Somers free(entry); 3687d96f4efSBrian Somers } 3697d96f4efSBrian Somers 3707d96f4efSBrian Somers static int 3715e289f9eSPoul-Henning Kamp RuleNumberDelete(struct libalias *la, int rule_index) 3727d96f4efSBrian Somers { 3737d96f4efSBrian Somers int err; 3747d96f4efSBrian Somers struct proxy_entry *ptr; 3757d96f4efSBrian Somers 376ccd57eeaSPaolo Pisati LIBALIAS_LOCK_ASSERT(la); 3777d96f4efSBrian Somers err = -1; 3785e289f9eSPoul-Henning Kamp ptr = la->proxyList; 379f0f93429SDag-Erling Smørgrav while (ptr != NULL) { 3807d96f4efSBrian Somers struct proxy_entry *ptr_next; 3817d96f4efSBrian Somers 3827d96f4efSBrian Somers ptr_next = ptr->next; 383f0f93429SDag-Erling Smørgrav if (ptr->rule_index == rule_index) { 3847d96f4efSBrian Somers err = 0; 3857d96f4efSBrian Somers RuleDelete(ptr); 3867d96f4efSBrian Somers } 3877d96f4efSBrian Somers ptr = ptr_next; 3887d96f4efSBrian Somers } 3897d96f4efSBrian Somers 390ffcb611aSDag-Erling Smørgrav return (err); 3917d96f4efSBrian Somers } 3927d96f4efSBrian Somers 3937d96f4efSBrian Somers static void 394ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(struct alias_link *lnk, 3957d96f4efSBrian Somers struct ip *pip, 3967d96f4efSBrian Somers int maxpacketsize) 3977d96f4efSBrian Somers { 3987d96f4efSBrian Somers int slen; 3997d96f4efSBrian Somers char buffer[40]; 4007d96f4efSBrian Somers struct tcphdr *tc; 4017d96f4efSBrian Somers 4027d96f4efSBrian Somers /* Compute pointer to tcp header */ 4039fa0fd26SDag-Erling Smørgrav tc = (struct tcphdr *)ip_next(pip); 4047d96f4efSBrian Somers 4057d96f4efSBrian Somers /* Don't modify if once already modified */ 4067d96f4efSBrian Somers 407ed01a582SDag-Erling Smørgrav if (GetAckModified(lnk)) 4087d96f4efSBrian Somers return; 4097d96f4efSBrian Somers 4107d96f4efSBrian Somers /* Translate destination address and port to string form */ 4117d96f4efSBrian Somers snprintf(buffer, sizeof(buffer) - 2, "[DEST %s %d]", 412ed01a582SDag-Erling Smørgrav inet_ntoa(GetProxyAddress(lnk)), (u_int) ntohs(GetProxyPort(lnk))); 4137d96f4efSBrian Somers 4147d96f4efSBrian Somers /* Pad string out to a multiple of two in length */ 4157d96f4efSBrian Somers slen = strlen(buffer); 416f0f93429SDag-Erling Smørgrav switch (slen % 2) { 4177d96f4efSBrian Somers case 0: 4187d96f4efSBrian Somers strcat(buffer, " \n"); 4197d96f4efSBrian Somers slen += 2; 4207d96f4efSBrian Somers break; 4217d96f4efSBrian Somers case 1: 4227d96f4efSBrian Somers strcat(buffer, "\n"); 4237d96f4efSBrian Somers slen += 1; 4247d96f4efSBrian Somers } 4257d96f4efSBrian Somers 4267d96f4efSBrian Somers /* Check for packet overflow */ 427ed01a582SDag-Erling Smørgrav if ((int)(ntohs(pip->ip_len) + strlen(buffer)) > maxpacketsize) 4287d96f4efSBrian Somers return; 4297d96f4efSBrian Somers 4307d96f4efSBrian Somers /* Shift existing TCP data and insert destination string */ 4317d96f4efSBrian Somers { 4327d96f4efSBrian Somers int dlen; 4337d96f4efSBrian Somers int hlen; 4347d96f4efSBrian Somers u_char *p; 4357d96f4efSBrian Somers 4367d96f4efSBrian Somers hlen = (pip->ip_hl + tc->th_off) << 2; 4377d96f4efSBrian Somers dlen = ntohs(pip->ip_len) - hlen; 4387d96f4efSBrian Somers 4397d96f4efSBrian Somers /* Modify first packet that has data in it */ 4407d96f4efSBrian Somers 4417d96f4efSBrian Somers if (dlen == 0) 4427d96f4efSBrian Somers return; 4437d96f4efSBrian Somers 4447d96f4efSBrian Somers p = (char *)pip; 4457d96f4efSBrian Somers p += hlen; 4467d96f4efSBrian Somers 447c8d3ca72SGleb Smirnoff bcopy(p, p + slen, dlen); 4487d96f4efSBrian Somers memcpy(p, buffer, slen); 4497d96f4efSBrian Somers } 4507d96f4efSBrian Somers 4517d96f4efSBrian Somers /* Save information about modfied sequence number */ 4527d96f4efSBrian Somers { 4537d96f4efSBrian Somers int delta; 4547d96f4efSBrian Somers 455ed01a582SDag-Erling Smørgrav SetAckModified(lnk); 456ed01a582SDag-Erling Smørgrav delta = GetDeltaSeqOut(pip, lnk); 457ed01a582SDag-Erling Smørgrav AddSeq(pip, lnk, delta + slen); 4587d96f4efSBrian Somers } 4597d96f4efSBrian Somers 4607d96f4efSBrian Somers /* Update IP header packet length and checksum */ 4617d96f4efSBrian Somers { 4627d96f4efSBrian Somers int accumulate; 4637d96f4efSBrian Somers 4647d96f4efSBrian Somers accumulate = pip->ip_len; 4657d96f4efSBrian Somers pip->ip_len = htons(ntohs(pip->ip_len) + slen); 4667d96f4efSBrian Somers accumulate -= pip->ip_len; 4677d96f4efSBrian Somers 4687d96f4efSBrian Somers ADJUST_CHECKSUM(accumulate, pip->ip_sum); 4697d96f4efSBrian Somers } 4707d96f4efSBrian Somers 4717d96f4efSBrian Somers /* Update TCP checksum, Use TcpChecksum since so many things have 4727d96f4efSBrian Somers already changed. */ 4737d96f4efSBrian Somers 4747d96f4efSBrian Somers tc->th_sum = 0; 47559dde15eSGleb Smirnoff #ifdef _KERNEL 47659dde15eSGleb Smirnoff tc->th_x2 = 1; 47759dde15eSGleb Smirnoff #else 4787d96f4efSBrian Somers tc->th_sum = TcpChecksum(pip); 47959dde15eSGleb Smirnoff #endif 4807d96f4efSBrian Somers } 4817d96f4efSBrian Somers 4827d96f4efSBrian Somers static void 4837d96f4efSBrian Somers ProxyEncodeIpHeader(struct ip *pip, 4847d96f4efSBrian Somers int maxpacketsize) 4857d96f4efSBrian Somers { 4867d96f4efSBrian Somers #define OPTION_LEN_BYTES 8 4877d96f4efSBrian Somers #define OPTION_LEN_INT16 4 4887d96f4efSBrian Somers #define OPTION_LEN_INT32 2 4897d96f4efSBrian Somers u_char option[OPTION_LEN_BYTES]; 4907d96f4efSBrian Somers 4916293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG 4927d96f4efSBrian Somers fprintf(stdout, " ip cksum 1 = %x\n", (u_int) IpChecksum(pip)); 4937d96f4efSBrian Somers fprintf(stdout, "tcp cksum 1 = %x\n", (u_int) TcpChecksum(pip)); 4944c32f5d2SBrian Somers #endif 4957d96f4efSBrian Somers 496ed01a582SDag-Erling Smørgrav (void)maxpacketsize; 497ed01a582SDag-Erling Smørgrav 4987d96f4efSBrian Somers /* Check to see that there is room to add an IP option */ 4997d96f4efSBrian Somers if (pip->ip_hl > (0x0f - OPTION_LEN_INT32)) 5007d96f4efSBrian Somers return; 5017d96f4efSBrian Somers 5027d96f4efSBrian Somers /* Build option and copy into packet */ 5037d96f4efSBrian Somers { 5047d96f4efSBrian Somers u_char *ptr; 5057d96f4efSBrian Somers struct tcphdr *tc; 5067d96f4efSBrian Somers 5077d96f4efSBrian Somers ptr = (u_char *) pip; 5087d96f4efSBrian Somers ptr += 20; 5097d96f4efSBrian Somers memcpy(ptr + OPTION_LEN_BYTES, ptr, ntohs(pip->ip_len) - 20); 5107d96f4efSBrian Somers 5117d96f4efSBrian Somers option[0] = 0x64; /* class: 3 (reserved), option 4 */ 5127d96f4efSBrian Somers option[1] = OPTION_LEN_BYTES; 5137d96f4efSBrian Somers 5147d96f4efSBrian Somers memcpy(&option[2], (u_char *) & pip->ip_dst, 4); 5157d96f4efSBrian Somers 5169fa0fd26SDag-Erling Smørgrav tc = (struct tcphdr *)ip_next(pip); 5177d96f4efSBrian Somers memcpy(&option[6], (u_char *) & tc->th_sport, 2); 5187d96f4efSBrian Somers 5197d96f4efSBrian Somers memcpy(ptr, option, 8); 5207d96f4efSBrian Somers } 5217d96f4efSBrian Somers 5227d96f4efSBrian Somers /* Update checksum, header length and packet length */ 5237d96f4efSBrian Somers { 5247d96f4efSBrian Somers int i; 5257d96f4efSBrian Somers int accumulate; 5267d96f4efSBrian Somers u_short *sptr; 5277d96f4efSBrian Somers 5287d96f4efSBrian Somers sptr = (u_short *) option; 5297d96f4efSBrian Somers accumulate = 0; 5307d96f4efSBrian Somers for (i = 0; i < OPTION_LEN_INT16; i++) 5317d96f4efSBrian Somers accumulate -= *(sptr++); 5327d96f4efSBrian Somers 5337d96f4efSBrian Somers sptr = (u_short *) pip; 5347d96f4efSBrian Somers accumulate += *sptr; 5357d96f4efSBrian Somers pip->ip_hl += OPTION_LEN_INT32; 5367d96f4efSBrian Somers accumulate -= *sptr; 5377d96f4efSBrian Somers 5387d96f4efSBrian Somers accumulate += pip->ip_len; 5397d96f4efSBrian Somers pip->ip_len = htons(ntohs(pip->ip_len) + OPTION_LEN_BYTES); 5407d96f4efSBrian Somers accumulate -= pip->ip_len; 5417d96f4efSBrian Somers 5427d96f4efSBrian Somers ADJUST_CHECKSUM(accumulate, pip->ip_sum); 5437d96f4efSBrian Somers } 5447d96f4efSBrian Somers #undef OPTION_LEN_BYTES 5457d96f4efSBrian Somers #undef OPTION_LEN_INT16 5467d96f4efSBrian Somers #undef OPTION_LEN_INT32 5476293e003SGleb Smirnoff #ifdef LIBALIAS_DEBUG 5487d96f4efSBrian Somers fprintf(stdout, " ip cksum 2 = %x\n", (u_int) IpChecksum(pip)); 5497d96f4efSBrian Somers fprintf(stdout, "tcp cksum 2 = %x\n", (u_int) TcpChecksum(pip)); 5504c32f5d2SBrian Somers #endif 5517d96f4efSBrian Somers } 5527d96f4efSBrian Somers 5537d96f4efSBrian Somers 5547d96f4efSBrian Somers /* Functions by other packet alias source files 5557d96f4efSBrian Somers 5567d96f4efSBrian Somers ProxyCheck() -- Checks whether an outgoing packet should 5577d96f4efSBrian Somers be proxied. 5587d96f4efSBrian Somers ProxyModify() -- Encodes the original destination address/port 5597d96f4efSBrian Somers for a packet which is to be redirected to 5607d96f4efSBrian Somers a proxy server. 5617d96f4efSBrian Somers */ 5627d96f4efSBrian Somers 5637d96f4efSBrian Somers int 5645e289f9eSPoul-Henning Kamp ProxyCheck(struct libalias *la, struct ip *pip, 5657d96f4efSBrian Somers struct in_addr *proxy_server_addr, 5667d96f4efSBrian Somers u_short * proxy_server_port) 5677d96f4efSBrian Somers { 5687d96f4efSBrian Somers u_short dst_port; 5697d96f4efSBrian Somers struct in_addr src_addr; 5707d96f4efSBrian Somers struct in_addr dst_addr; 5717d96f4efSBrian Somers struct proxy_entry *ptr; 5727d96f4efSBrian Somers 573ccd57eeaSPaolo Pisati LIBALIAS_LOCK_ASSERT(la); 5747d96f4efSBrian Somers src_addr = pip->ip_src; 5757d96f4efSBrian Somers dst_addr = pip->ip_dst; 5769fa0fd26SDag-Erling Smørgrav dst_port = ((struct tcphdr *)ip_next(pip)) 5777d96f4efSBrian Somers ->th_dport; 5787d96f4efSBrian Somers 5795e289f9eSPoul-Henning Kamp ptr = la->proxyList; 580f0f93429SDag-Erling Smørgrav while (ptr != NULL) { 5817d96f4efSBrian Somers u_short proxy_port; 5827d96f4efSBrian Somers 5837d96f4efSBrian Somers proxy_port = ptr->proxy_port; 5847d96f4efSBrian Somers if ((dst_port == proxy_port || proxy_port == 0) 5857d96f4efSBrian Somers && pip->ip_p == ptr->proto 586f0f93429SDag-Erling Smørgrav && src_addr.s_addr != ptr->server_addr.s_addr) { 5877d96f4efSBrian Somers struct in_addr src_addr_masked; 5887d96f4efSBrian Somers struct in_addr dst_addr_masked; 5897d96f4efSBrian Somers 5907d96f4efSBrian Somers src_addr_masked.s_addr = src_addr.s_addr & ptr->src_mask.s_addr; 5917d96f4efSBrian Somers dst_addr_masked.s_addr = dst_addr.s_addr & ptr->dst_mask.s_addr; 5927d96f4efSBrian Somers 5937d96f4efSBrian Somers if ((src_addr_masked.s_addr == ptr->src_addr.s_addr) 594f0f93429SDag-Erling Smørgrav && (dst_addr_masked.s_addr == ptr->dst_addr.s_addr)) { 5957d96f4efSBrian Somers if ((*proxy_server_port = ptr->server_port) == 0) 5967d96f4efSBrian Somers *proxy_server_port = dst_port; 5977d96f4efSBrian Somers *proxy_server_addr = ptr->server_addr; 598ffcb611aSDag-Erling Smørgrav return (ptr->proxy_type); 5997d96f4efSBrian Somers } 6007d96f4efSBrian Somers } 6017d96f4efSBrian Somers ptr = ptr->next; 6027d96f4efSBrian Somers } 6037d96f4efSBrian Somers 604ffcb611aSDag-Erling Smørgrav return (0); 6057d96f4efSBrian Somers } 6067d96f4efSBrian Somers 6077d96f4efSBrian Somers void 608ed01a582SDag-Erling Smørgrav ProxyModify(struct libalias *la, struct alias_link *lnk, 6097d96f4efSBrian Somers struct ip *pip, 6107d96f4efSBrian Somers int maxpacketsize, 6117d96f4efSBrian Somers int proxy_type) 6127d96f4efSBrian Somers { 613ed01a582SDag-Erling Smørgrav 614ccd57eeaSPaolo Pisati LIBALIAS_LOCK_ASSERT(la); 615ed01a582SDag-Erling Smørgrav (void)la; 616ed01a582SDag-Erling Smørgrav 617f0f93429SDag-Erling Smørgrav switch (proxy_type) { 6187d96f4efSBrian Somers case PROXY_TYPE_ENCODE_IPHDR: 6197d96f4efSBrian Somers ProxyEncodeIpHeader(pip, maxpacketsize); 6207d96f4efSBrian Somers break; 6217d96f4efSBrian Somers 6227d96f4efSBrian Somers case PROXY_TYPE_ENCODE_TCPSTREAM: 623ed01a582SDag-Erling Smørgrav ProxyEncodeTcpStream(lnk, pip, maxpacketsize); 6247d96f4efSBrian Somers break; 6257d96f4efSBrian Somers } 6267d96f4efSBrian Somers } 6277d96f4efSBrian Somers 6287d96f4efSBrian Somers 6297d96f4efSBrian Somers /* 6307d96f4efSBrian Somers Public API functions 6317d96f4efSBrian Somers */ 6327d96f4efSBrian Somers 6337d96f4efSBrian Somers int 6345e289f9eSPoul-Henning Kamp LibAliasProxyRule(struct libalias *la, const char *cmd) 6357d96f4efSBrian Somers { 6367d96f4efSBrian Somers /* 6377d96f4efSBrian Somers * This function takes command strings of the form: 6387d96f4efSBrian Somers * 6397d96f4efSBrian Somers * server <addr>[:<port>] 6407d96f4efSBrian Somers * [port <port>] 6417d96f4efSBrian Somers * [rule n] 6427d96f4efSBrian Somers * [proto tcp|udp] 6437d96f4efSBrian Somers * [src <addr>[/n]] 6447d96f4efSBrian Somers * [dst <addr>[/n]] 6457d96f4efSBrian Somers * [type encode_tcp_stream|encode_ip_hdr|no_encode] 6467d96f4efSBrian Somers * 6477d96f4efSBrian Somers * delete <rule number> 6487d96f4efSBrian Somers * 6497d96f4efSBrian Somers * Subfields can be in arbitrary order. Port numbers and addresses 6507d96f4efSBrian Somers * must be in either numeric or symbolic form. An optional rule number 6517d96f4efSBrian Somers * is used to control the order in which rules are searched. If two 6527d96f4efSBrian Somers * rules have the same number, then search order cannot be guaranteed, 6537d96f4efSBrian Somers * and the rules should be disjoint. If no rule number is specified, 6547d96f4efSBrian Somers * then 0 is used, and group 0 rules are always checked before any 6557d96f4efSBrian Somers * others. 6567d96f4efSBrian Somers */ 657ccd57eeaSPaolo Pisati int i, n, len, ret; 6587d96f4efSBrian Somers int cmd_len; 6597d96f4efSBrian Somers int token_count; 6607d96f4efSBrian Somers int state; 6617d96f4efSBrian Somers char *token; 6627d96f4efSBrian Somers char buffer[256]; 6637d96f4efSBrian Somers char str_port[sizeof(buffer)]; 6647d96f4efSBrian Somers char str_server_port[sizeof(buffer)]; 665d9e630b5SAndrey A. Chernov char *res = buffer; 6667d96f4efSBrian Somers 6677d96f4efSBrian Somers int rule_index; 6687d96f4efSBrian Somers int proto; 6697d96f4efSBrian Somers int proxy_type; 6707d96f4efSBrian Somers int proxy_port; 6717d96f4efSBrian Somers int server_port; 6727d96f4efSBrian Somers struct in_addr server_addr; 6737d96f4efSBrian Somers struct in_addr src_addr, src_mask; 6747d96f4efSBrian Somers struct in_addr dst_addr, dst_mask; 6757d96f4efSBrian Somers struct proxy_entry *proxy_entry; 6767d96f4efSBrian Somers 677ccd57eeaSPaolo Pisati LIBALIAS_LOCK(la); 678ccd57eeaSPaolo Pisati ret = 0; 6797d96f4efSBrian Somers /* Copy command line into a buffer */ 6804834b77dSBrian Somers cmd += strspn(cmd, " \t"); 6817d96f4efSBrian Somers cmd_len = strlen(cmd); 682ccd57eeaSPaolo Pisati if (cmd_len > (int)(sizeof(buffer) - 1)) { 683ccd57eeaSPaolo Pisati ret = -1; 684ccd57eeaSPaolo Pisati goto getout; 685ccd57eeaSPaolo Pisati } 6867d96f4efSBrian Somers strcpy(buffer, cmd); 6877d96f4efSBrian Somers 6887d96f4efSBrian Somers /* Convert to lower case */ 6897d96f4efSBrian Somers len = strlen(buffer); 6907d96f4efSBrian Somers for (i = 0; i < len; i++) 691d9e630b5SAndrey A. Chernov buffer[i] = tolower((unsigned char)buffer[i]); 6927d96f4efSBrian Somers 6937d96f4efSBrian Somers /* Set default proxy type */ 6947d96f4efSBrian Somers 6957d96f4efSBrian Somers /* Set up default values */ 6967d96f4efSBrian Somers rule_index = 0; 6977d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_NONE; 6987d96f4efSBrian Somers proto = IPPROTO_TCP; 6997d96f4efSBrian Somers proxy_port = 0; 7007d96f4efSBrian Somers server_addr.s_addr = 0; 7017d96f4efSBrian Somers server_port = 0; 7027d96f4efSBrian Somers src_addr.s_addr = 0; 7037d96f4efSBrian Somers IpMask(0, &src_mask); 7047d96f4efSBrian Somers dst_addr.s_addr = 0; 7057d96f4efSBrian Somers IpMask(0, &dst_mask); 7067d96f4efSBrian Somers 7077d96f4efSBrian Somers str_port[0] = 0; 7087d96f4efSBrian Somers str_server_port[0] = 0; 7097d96f4efSBrian Somers 7107d96f4efSBrian Somers /* Parse command string with state machine */ 7117d96f4efSBrian Somers #define STATE_READ_KEYWORD 0 7127d96f4efSBrian Somers #define STATE_READ_TYPE 1 7137d96f4efSBrian Somers #define STATE_READ_PORT 2 7147d96f4efSBrian Somers #define STATE_READ_SERVER 3 7157d96f4efSBrian Somers #define STATE_READ_RULE 4 7167d96f4efSBrian Somers #define STATE_READ_DELETE 5 7177d96f4efSBrian Somers #define STATE_READ_PROTO 6 7187d96f4efSBrian Somers #define STATE_READ_SRC 7 7197d96f4efSBrian Somers #define STATE_READ_DST 8 7207d96f4efSBrian Somers state = STATE_READ_KEYWORD; 721d9e630b5SAndrey A. Chernov token = strsep(&res, " \t"); 7227d96f4efSBrian Somers token_count = 0; 723f0f93429SDag-Erling Smørgrav while (token != NULL) { 7247d96f4efSBrian Somers token_count++; 725f0f93429SDag-Erling Smørgrav switch (state) { 7267d96f4efSBrian Somers case STATE_READ_KEYWORD: 7277d96f4efSBrian Somers if (strcmp(token, "type") == 0) 7287d96f4efSBrian Somers state = STATE_READ_TYPE; 7297d96f4efSBrian Somers else if (strcmp(token, "port") == 0) 7307d96f4efSBrian Somers state = STATE_READ_PORT; 7317d96f4efSBrian Somers else if (strcmp(token, "server") == 0) 7327d96f4efSBrian Somers state = STATE_READ_SERVER; 7337d96f4efSBrian Somers else if (strcmp(token, "rule") == 0) 7347d96f4efSBrian Somers state = STATE_READ_RULE; 7357d96f4efSBrian Somers else if (strcmp(token, "delete") == 0) 7367d96f4efSBrian Somers state = STATE_READ_DELETE; 7377d96f4efSBrian Somers else if (strcmp(token, "proto") == 0) 7387d96f4efSBrian Somers state = STATE_READ_PROTO; 7397d96f4efSBrian Somers else if (strcmp(token, "src") == 0) 7407d96f4efSBrian Somers state = STATE_READ_SRC; 7417d96f4efSBrian Somers else if (strcmp(token, "dst") == 0) 7427d96f4efSBrian Somers state = STATE_READ_DST; 743ccd57eeaSPaolo Pisati else { 744ccd57eeaSPaolo Pisati ret = -1; 745ccd57eeaSPaolo Pisati goto getout; 746ccd57eeaSPaolo Pisati } 7477d96f4efSBrian Somers break; 7487d96f4efSBrian Somers 7497d96f4efSBrian Somers case STATE_READ_TYPE: 7507d96f4efSBrian Somers if (strcmp(token, "encode_ip_hdr") == 0) 7517d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_IPHDR; 7527d96f4efSBrian Somers else if (strcmp(token, "encode_tcp_stream") == 0) 7537d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_TCPSTREAM; 7547d96f4efSBrian Somers else if (strcmp(token, "no_encode") == 0) 7557d96f4efSBrian Somers proxy_type = PROXY_TYPE_ENCODE_NONE; 756ccd57eeaSPaolo Pisati else { 757ccd57eeaSPaolo Pisati ret = -1; 758ccd57eeaSPaolo Pisati goto getout; 759ccd57eeaSPaolo Pisati } 7607d96f4efSBrian Somers state = STATE_READ_KEYWORD; 7617d96f4efSBrian Somers break; 7627d96f4efSBrian Somers 7637d96f4efSBrian Somers case STATE_READ_PORT: 7647d96f4efSBrian Somers strcpy(str_port, token); 7657d96f4efSBrian Somers state = STATE_READ_KEYWORD; 7667d96f4efSBrian Somers break; 7677d96f4efSBrian Somers 7687d96f4efSBrian Somers case STATE_READ_SERVER: 7697d96f4efSBrian Somers { 7707d96f4efSBrian Somers int err; 7717d96f4efSBrian Somers char *p; 7727d96f4efSBrian Somers char s[sizeof(buffer)]; 7737d96f4efSBrian Somers 7747d96f4efSBrian Somers p = token; 7757d96f4efSBrian Somers while (*p != ':' && *p != 0) 7767d96f4efSBrian Somers p++; 7777d96f4efSBrian Somers 778f0f93429SDag-Erling Smørgrav if (*p != ':') { 7797d96f4efSBrian Somers err = IpAddr(token, &server_addr); 780ccd57eeaSPaolo Pisati if (err) { 781ccd57eeaSPaolo Pisati ret = -1; 782ccd57eeaSPaolo Pisati goto getout; 783ccd57eeaSPaolo Pisati } 784f0f93429SDag-Erling Smørgrav } else { 7857d96f4efSBrian Somers *p = ' '; 7867d96f4efSBrian Somers 7877d96f4efSBrian Somers n = sscanf(token, "%s %s", s, str_server_port); 788ccd57eeaSPaolo Pisati if (n != 2) { 789ccd57eeaSPaolo Pisati ret = -1; 790ccd57eeaSPaolo Pisati goto getout; 791ccd57eeaSPaolo Pisati } 7927d96f4efSBrian Somers 7937d96f4efSBrian Somers err = IpAddr(s, &server_addr); 794ccd57eeaSPaolo Pisati if (err) { 795ccd57eeaSPaolo Pisati ret = -1; 796ccd57eeaSPaolo Pisati goto getout; 797ccd57eeaSPaolo Pisati } 7987d96f4efSBrian Somers } 7997d96f4efSBrian Somers } 8007d96f4efSBrian Somers state = STATE_READ_KEYWORD; 8017d96f4efSBrian Somers break; 8027d96f4efSBrian Somers 8037d96f4efSBrian Somers case STATE_READ_RULE: 8047d96f4efSBrian Somers n = sscanf(token, "%d", &rule_index); 805ccd57eeaSPaolo Pisati if (n != 1 || rule_index < 0) { 806ccd57eeaSPaolo Pisati ret = -1; 807ccd57eeaSPaolo Pisati goto getout; 808ccd57eeaSPaolo Pisati } 8097d96f4efSBrian Somers state = STATE_READ_KEYWORD; 8107d96f4efSBrian Somers break; 8117d96f4efSBrian Somers 8127d96f4efSBrian Somers case STATE_READ_DELETE: 8137d96f4efSBrian Somers { 8147d96f4efSBrian Somers int err; 8157d96f4efSBrian Somers int rule_to_delete; 8167d96f4efSBrian Somers 817ccd57eeaSPaolo Pisati if (token_count != 2) { 818ccd57eeaSPaolo Pisati ret = -1; 819ccd57eeaSPaolo Pisati goto getout; 820ccd57eeaSPaolo Pisati } 8217d96f4efSBrian Somers 8227d96f4efSBrian Somers n = sscanf(token, "%d", &rule_to_delete); 823ccd57eeaSPaolo Pisati if (n != 1) { 824ccd57eeaSPaolo Pisati ret = -1; 825ccd57eeaSPaolo Pisati goto getout; 826ccd57eeaSPaolo Pisati } 8275e289f9eSPoul-Henning Kamp err = RuleNumberDelete(la, rule_to_delete); 8287d96f4efSBrian Somers if (err) 829ccd57eeaSPaolo Pisati ret = -1; 830ccd57eeaSPaolo Pisati ret = 0; 831ccd57eeaSPaolo Pisati goto getout; 8327d96f4efSBrian Somers } 8337d96f4efSBrian Somers 8347d96f4efSBrian Somers case STATE_READ_PROTO: 8357d96f4efSBrian Somers if (strcmp(token, "tcp") == 0) 8367d96f4efSBrian Somers proto = IPPROTO_TCP; 8377d96f4efSBrian Somers else if (strcmp(token, "udp") == 0) 8387d96f4efSBrian Somers proto = IPPROTO_UDP; 839ccd57eeaSPaolo Pisati else { 840ccd57eeaSPaolo Pisati ret = -1; 841ccd57eeaSPaolo Pisati goto getout; 842ccd57eeaSPaolo Pisati } 8437d96f4efSBrian Somers state = STATE_READ_KEYWORD; 8447d96f4efSBrian Somers break; 8457d96f4efSBrian Somers 8467d96f4efSBrian Somers case STATE_READ_SRC: 8477d96f4efSBrian Somers case STATE_READ_DST: 8487d96f4efSBrian Somers { 8497d96f4efSBrian Somers int err; 8507d96f4efSBrian Somers char *p; 8517d96f4efSBrian Somers struct in_addr mask; 8527d96f4efSBrian Somers struct in_addr addr; 8537d96f4efSBrian Somers 8547d96f4efSBrian Somers p = token; 8557d96f4efSBrian Somers while (*p != '/' && *p != 0) 8567d96f4efSBrian Somers p++; 8577d96f4efSBrian Somers 858f0f93429SDag-Erling Smørgrav if (*p != '/') { 8597d96f4efSBrian Somers IpMask(32, &mask); 8607d96f4efSBrian Somers err = IpAddr(token, &addr); 861ccd57eeaSPaolo Pisati if (err) { 862ccd57eeaSPaolo Pisati ret = -1; 863ccd57eeaSPaolo Pisati goto getout; 864ccd57eeaSPaolo Pisati } 865f0f93429SDag-Erling Smørgrav } else { 8667d96f4efSBrian Somers int nbits; 8677d96f4efSBrian Somers char s[sizeof(buffer)]; 8687d96f4efSBrian Somers 8697d96f4efSBrian Somers *p = ' '; 8707d96f4efSBrian Somers n = sscanf(token, "%s %d", s, &nbits); 871ccd57eeaSPaolo Pisati if (n != 2) { 872ccd57eeaSPaolo Pisati ret = -1; 873ccd57eeaSPaolo Pisati goto getout; 874ccd57eeaSPaolo Pisati } 8757d96f4efSBrian Somers 8767d96f4efSBrian Somers err = IpAddr(s, &addr); 877ccd57eeaSPaolo Pisati if (err) { 878ccd57eeaSPaolo Pisati ret = -1; 879ccd57eeaSPaolo Pisati goto getout; 880ccd57eeaSPaolo Pisati } 8817d96f4efSBrian Somers 8827d96f4efSBrian Somers err = IpMask(nbits, &mask); 883ccd57eeaSPaolo Pisati if (err) { 884ccd57eeaSPaolo Pisati ret = -1; 885ccd57eeaSPaolo Pisati goto getout; 886ccd57eeaSPaolo Pisati } 8877d96f4efSBrian Somers } 8887d96f4efSBrian Somers 889f0f93429SDag-Erling Smørgrav if (state == STATE_READ_SRC) { 8907d96f4efSBrian Somers src_addr = addr; 8917d96f4efSBrian Somers src_mask = mask; 892f0f93429SDag-Erling Smørgrav } else { 8937d96f4efSBrian Somers dst_addr = addr; 8947d96f4efSBrian Somers dst_mask = mask; 8957d96f4efSBrian Somers } 8967d96f4efSBrian Somers } 8977d96f4efSBrian Somers state = STATE_READ_KEYWORD; 8987d96f4efSBrian Somers break; 8997d96f4efSBrian Somers 9007d96f4efSBrian Somers default: 901ccd57eeaSPaolo Pisati ret = -1; 902ccd57eeaSPaolo Pisati goto getout; 9037d96f4efSBrian Somers break; 9047d96f4efSBrian Somers } 9057d96f4efSBrian Somers 906d9e630b5SAndrey A. Chernov do { 907d9e630b5SAndrey A. Chernov token = strsep(&res, " \t"); 908d9e630b5SAndrey A. Chernov } while (token != NULL && !*token); 9097d96f4efSBrian Somers } 9107d96f4efSBrian Somers #undef STATE_READ_KEYWORD 9117d96f4efSBrian Somers #undef STATE_READ_TYPE 9127d96f4efSBrian Somers #undef STATE_READ_PORT 9137d96f4efSBrian Somers #undef STATE_READ_SERVER 9147d96f4efSBrian Somers #undef STATE_READ_RULE 9157d96f4efSBrian Somers #undef STATE_READ_DELETE 9167d96f4efSBrian Somers #undef STATE_READ_PROTO 9177d96f4efSBrian Somers #undef STATE_READ_SRC 9187d96f4efSBrian Somers #undef STATE_READ_DST 9197d96f4efSBrian Somers 9207d96f4efSBrian Somers /* Convert port strings to numbers. This needs to be done after 9217d96f4efSBrian Somers the string is parsed, because the prototype might not be designated 9227d96f4efSBrian Somers before the ports (which might be symbolic entries in /etc/services) */ 9237d96f4efSBrian Somers 924f0f93429SDag-Erling Smørgrav if (strlen(str_port) != 0) { 9257d96f4efSBrian Somers int err; 9267d96f4efSBrian Somers 9277d96f4efSBrian Somers err = IpPort(str_port, proto, &proxy_port); 928ccd57eeaSPaolo Pisati if (err) { 929ccd57eeaSPaolo Pisati ret = -1; 930ccd57eeaSPaolo Pisati goto getout; 931ccd57eeaSPaolo Pisati } 932f0f93429SDag-Erling Smørgrav } else { 9337d96f4efSBrian Somers proxy_port = 0; 9347d96f4efSBrian Somers } 9357d96f4efSBrian Somers 936f0f93429SDag-Erling Smørgrav if (strlen(str_server_port) != 0) { 9377d96f4efSBrian Somers int err; 9387d96f4efSBrian Somers 9397d96f4efSBrian Somers err = IpPort(str_server_port, proto, &server_port); 940ccd57eeaSPaolo Pisati if (err) { 941ccd57eeaSPaolo Pisati ret = -1; 942ccd57eeaSPaolo Pisati goto getout; 943ccd57eeaSPaolo Pisati } 944f0f93429SDag-Erling Smørgrav } else { 9457d96f4efSBrian Somers server_port = 0; 9467d96f4efSBrian Somers } 9477d96f4efSBrian Somers 9487d96f4efSBrian Somers /* Check that at least the server address has been defined */ 949ccd57eeaSPaolo Pisati if (server_addr.s_addr == 0) { 950ccd57eeaSPaolo Pisati ret = -1; 951ccd57eeaSPaolo Pisati goto getout; 952ccd57eeaSPaolo Pisati } 9537d96f4efSBrian Somers 9547d96f4efSBrian Somers /* Add to linked list */ 9557d96f4efSBrian Somers proxy_entry = malloc(sizeof(struct proxy_entry)); 956ccd57eeaSPaolo Pisati if (proxy_entry == NULL) { 957ccd57eeaSPaolo Pisati ret = -1; 958ccd57eeaSPaolo Pisati goto getout; 959ccd57eeaSPaolo Pisati } 9607d96f4efSBrian Somers 9617d96f4efSBrian Somers proxy_entry->proxy_type = proxy_type; 9627d96f4efSBrian Somers proxy_entry->rule_index = rule_index; 9637d96f4efSBrian Somers proxy_entry->proto = proto; 9647d96f4efSBrian Somers proxy_entry->proxy_port = htons(proxy_port); 9657d96f4efSBrian Somers proxy_entry->server_port = htons(server_port); 9667d96f4efSBrian Somers proxy_entry->server_addr = server_addr; 9677d96f4efSBrian Somers proxy_entry->src_addr.s_addr = src_addr.s_addr & src_mask.s_addr; 9687d96f4efSBrian Somers proxy_entry->dst_addr.s_addr = dst_addr.s_addr & dst_mask.s_addr; 9697d96f4efSBrian Somers proxy_entry->src_mask = src_mask; 9707d96f4efSBrian Somers proxy_entry->dst_mask = dst_mask; 9717d96f4efSBrian Somers 9725e289f9eSPoul-Henning Kamp RuleAdd(la, proxy_entry); 9737d96f4efSBrian Somers 974ccd57eeaSPaolo Pisati getout: 975ccd57eeaSPaolo Pisati LIBALIAS_UNLOCK(la); 976ccd57eeaSPaolo Pisati return (ret); 9777d96f4efSBrian Somers } 978