177701Sbrian/*- 285964Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net> 377701Sbrian * All rights reserved. 477701Sbrian * 577701Sbrian * Redistribution and use in source and binary forms, with or without 677701Sbrian * modification, are permitted provided that the following conditions 777701Sbrian * are met: 877701Sbrian * 1. Redistributions of source code must retain the above copyright 977701Sbrian * notice, this list of conditions and the following disclaimer. 1077701Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1177701Sbrian * notice, this list of conditions and the following disclaimer in the 1277701Sbrian * documentation and/or other materials provided with the distribution. 1377701Sbrian * 1477701Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1577701Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1677701Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1777701Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1877701Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1977701Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2077701Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2177701Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2277701Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2377701Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2477701Sbrian * SUCH DAMAGE. 2577701Sbrian */ 2677701Sbrian 2784195Sdillon#include <sys/cdefs.h> 2884195Sdillon__FBSDID("$FreeBSD: releng/10.3/sys/netinet/libalias/alias.c 248416 2013-03-17 07:37:10Z glebius $"); 2984195Sdillon 3026026Sbrian/* 3126026Sbrian Alias.c provides supervisory control for the functions of the 3226026Sbrian packet aliasing software. It consists of routines to monitor 3326026Sbrian TCP connection state, protocol-specific aliasing routines, 3426026Sbrian fragment handling and the following outside world functional 3526026Sbrian interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn, 3626026Sbrian PacketAliasIn and PacketAliasOut. 3726026Sbrian 3826026Sbrian The other C program files are briefly described. The data 3926026Sbrian structure framework which holds information needed to translate 4026026Sbrian packets is encapsulated in alias_db.c. Data is accessed by 4126026Sbrian function calls, so other segments of the program need not know 4226026Sbrian about the underlying data structures. Alias_ftp.c contains 4326026Sbrian special code for modifying the ftp PORT command used to establish 4459047Sru data connections, while alias_irc.c does the same for IRC 4526026Sbrian DCC. Alias_util.c contains a few utility routines. 4626026Sbrian 4726026Sbrian Version 1.0 August, 1996 (cjm) 4826026Sbrian 4926026Sbrian Version 1.1 August 20, 1996 (cjm) 50131612Sdes PPP host accepts incoming connections for ports 0 to 1023. 51131612Sdes (Gary Roberts pointed out the need to handle incoming 52131612Sdes connections.) 5326026Sbrian 5426026Sbrian Version 1.2 September 7, 1996 (cjm) 55131612Sdes Fragment handling error in alias_db.c corrected. 56131612Sdes (Tom Torrance helped fix this problem.) 5726026Sbrian 5826026Sbrian Version 1.4 September 16, 1996 (cjm) 59131612Sdes - A more generalized method for handling incoming 60131612Sdes connections, without the 0-1023 restriction, is 61131612Sdes implemented in alias_db.c 62131612Sdes - Improved ICMP support in alias.c. Traceroute 63131612Sdes packet streams can now be correctly aliased. 64131612Sdes - TCP connection closing logic simplified in 65131612Sdes alias.c and now allows for additional 1 minute 66131612Sdes "grace period" after FIN or RST is observed. 6726026Sbrian 6826026Sbrian Version 1.5 September 17, 1996 (cjm) 69131612Sdes Corrected error in handling incoming UDP packets with 0 checksum. 70131612Sdes (Tom Torrance helped fix this problem.) 7126026Sbrian 7226026Sbrian Version 1.6 September 18, 1996 (cjm) 73131612Sdes Simplified ICMP aliasing scheme. Should now support 74131612Sdes traceroute from Win95 as well as FreeBSD. 7526026Sbrian 7626026Sbrian Version 1.7 January 9, 1997 (cjm) 77131612Sdes - Out-of-order fragment handling. 78131612Sdes - IP checksum error fixed for ftp transfers 79131612Sdes from aliasing host. 80131612Sdes - Integer return codes added to all 81131612Sdes aliasing/de-aliasing functions. 82131612Sdes - Some obsolete comments cleaned up. 83131612Sdes - Differential checksum computations for 84131612Sdes IP header (TCP, UDP and ICMP were already 85131612Sdes differential). 8626026Sbrian 8726026Sbrian Version 2.1 May 1997 (cjm) 88131612Sdes - Added support for outgoing ICMP error 89131612Sdes messages. 90131612Sdes - Added two functions PacketAliasIn2() 91131612Sdes and PacketAliasOut2() for dynamic address 92131612Sdes control (e.g. round-robin allocation of 93131612Sdes incoming packets). 9427864Sbrian 9527864Sbrian Version 2.2 July 1997 (cjm) 96131612Sdes - Rationalized API function names to begin 97131612Sdes with "PacketAlias..." 98131612Sdes - Eliminated PacketAliasIn2() and 99131612Sdes PacketAliasOut2() as poorly conceived. 10027864Sbrian 10141759Sdillon Version 2.3 Dec 1998 (dillon) 10241759Sdillon - Major bounds checking additions, see FreeBSD/CVS 10341759Sdillon 10499207Sbrian Version 3.1 May, 2000 (salander) 10561861Sru - Added hooks to handle PPTP. 10661861Sru 10763899Sarchie Version 3.2 July, 2000 (salander and satoh) 10863899Sarchie - Added PacketUnaliasOut routine. 10963899Sarchie - Added hooks to handle RTSP/RTP. 11063899Sarchie 11132377Seivind See HISTORY file for additional revisions. 11226026Sbrian*/ 11326026Sbrian 114145921Sglebius#ifdef _KERNEL 115145921Sglebius#include <sys/param.h> 116164798Spiso#include <sys/systm.h> 117164798Spiso#include <sys/mbuf.h> 118188294Spiso#include <sys/sysctl.h> 119145921Sglebius#else 12026026Sbrian#include <sys/types.h> 121162674Spiso#include <stdlib.h> 122145921Sglebius#include <stdio.h> 123164798Spiso#include <ctype.h> 124162674Spiso#include <dlfcn.h> 125162674Spiso#include <errno.h> 126162674Spiso#include <string.h> 127145921Sglebius#endif 12826026Sbrian 12926026Sbrian#include <netinet/in_systm.h> 13026026Sbrian#include <netinet/in.h> 13126026Sbrian#include <netinet/ip.h> 13226026Sbrian#include <netinet/ip_icmp.h> 13326026Sbrian#include <netinet/tcp.h> 13426026Sbrian#include <netinet/udp.h> 13526026Sbrian 136145921Sglebius#ifdef _KERNEL 137145932Sglebius#include <netinet/libalias/alias.h> 138145921Sglebius#include <netinet/libalias/alias_local.h> 139162674Spiso#include <netinet/libalias/alias_mod.h> 140145921Sglebius#else 141162674Spiso#include <err.h> 142145932Sglebius#include "alias.h" 14326026Sbrian#include "alias_local.h" 144162674Spiso#include "alias_mod.h" 145145921Sglebius#endif 14626026Sbrian 147188294Spiso/* 148188294Spiso * Define libalias SYSCTL Node 149188294Spiso */ 150188294Spiso#ifdef SYSCTL_NODE 151188294Spiso 152188294SpisoSYSCTL_DECL(_net_inet); 153188294SpisoSYSCTL_DECL(_net_inet_ip); 154188294SpisoSYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW, NULL, "Libalias sysctl API"); 155188294Spiso 156188294Spiso#endif 157188294Spiso 158127689Sdesstatic __inline int 159127689Sdestwowords(void *p) 160127689Sdes{ 161131693Sdes uint8_t *c = p; 16226026Sbrian 163131693Sdes#if BYTE_ORDER == LITTLE_ENDIAN 164131693Sdes uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0]; 165131693Sdes uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2]; 166131693Sdes#else 167131693Sdes uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1]; 168131693Sdes uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3]; 169131693Sdes#endif 170131693Sdes return (s1 + s2); 171127689Sdes} 17226026Sbrian 17326026Sbrian/* TCP Handling Routines 17426026Sbrian 17526026Sbrian TcpMonitorIn() -- These routines monitor TCP connections, and 17644307Sbrian TcpMonitorOut() delete a link when a connection is closed. 17726026Sbrian 17851125SruThese routines look for SYN, FIN and RST flags to determine when TCP 17926026Sbrianconnections open and close. When a TCP connection closes, the data 18026026Sbrianstructure containing packet aliasing information is deleted after 18126026Sbriana timeout period. 18226026Sbrian*/ 18326026Sbrian 18426026Sbrian/* Local prototypes */ 185176884Spisostatic void TcpMonitorIn(u_char, struct alias_link *); 18626026Sbrian 187176884Spisostatic void TcpMonitorOut(u_char, struct alias_link *); 18826026Sbrian 18926026Sbrian 19026026Sbrianstatic void 191176884SpisoTcpMonitorIn(u_char th_flags, struct alias_link *lnk) 19226026Sbrian{ 19326026Sbrian 194131614Sdes switch (GetStateIn(lnk)) { 195127094Sdes case ALIAS_TCP_STATE_NOT_CONNECTED: 196176884Spiso if (th_flags & TH_RST) 197131614Sdes SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED); 198176884Spiso else if (th_flags & TH_SYN) 199131614Sdes SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED); 200127094Sdes break; 201127094Sdes case ALIAS_TCP_STATE_CONNECTED: 202176884Spiso if (th_flags & (TH_FIN | TH_RST)) 203131614Sdes SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED); 204127094Sdes break; 205127094Sdes } 20626026Sbrian} 20726026Sbrian 20826026Sbrianstatic void 209176884SpisoTcpMonitorOut(u_char th_flags, struct alias_link *lnk) 21026026Sbrian{ 21126026Sbrian 212131614Sdes switch (GetStateOut(lnk)) { 213127094Sdes case ALIAS_TCP_STATE_NOT_CONNECTED: 214176884Spiso if (th_flags & TH_RST) 215131614Sdes SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED); 216176884Spiso else if (th_flags & TH_SYN) 217131614Sdes SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED); 218127094Sdes break; 219127094Sdes case ALIAS_TCP_STATE_CONNECTED: 220176884Spiso if (th_flags & (TH_FIN | TH_RST)) 221131614Sdes SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED); 222127094Sdes break; 223127094Sdes } 22426026Sbrian} 22526026Sbrian 22626026Sbrian 22726026Sbrian 22826026Sbrian 22926026Sbrian 23099207Sbrian/* Protocol Specific Packet Aliasing Routines 23126026Sbrian 23265280Sru IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2() 23365280Sru IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2() 23459726Sru ProtoAliasIn(), ProtoAliasOut() 23526026Sbrian UdpAliasIn(), UdpAliasOut() 23626026Sbrian TcpAliasIn(), TcpAliasOut() 23726026Sbrian 23826026SbrianThese routines handle protocol specific details of packet aliasing. 23926026SbrianOne may observe a certain amount of repetitive arithmetic in these 24026026Sbrianfunctions, the purpose of which is to compute a revised checksum 24126026Sbrianwithout actually summing over the entire data packet, which could be 24226026Sbrianunnecessarily time consuming. 24326026Sbrian 24426026SbrianThe purpose of the packet aliasing routines is to replace the source 24526026Sbrianaddress of the outgoing packet and then correctly put it back for 24626026Sbrianany incoming packets. For TCP and UDP, ports are also re-mapped. 24726026Sbrian 24826026SbrianFor ICMP echo/timestamp requests and replies, the following scheme 24959356Sruis used: the ID number is replaced by an alias for the outgoing 25026026Sbrianpacket. 25126026Sbrian 25226026SbrianICMP error messages are handled by looking at the IP fragment 25326026Sbrianin the data section of the message. 25426026Sbrian 25526026SbrianFor TCP and UDP protocols, a port number is chosen for an outgoing 25626026Sbrianpacket, and then incoming packets are identified by IP address and 25726026Sbrianport numbers. For TCP packets, there is additional logic in the event 25859356Sruthat sequence and ACK numbers have been altered (as in the case for 25926026SbrianFTP data port commands). 26026026Sbrian 26126026SbrianThe port numbers used by the packet aliasing module are not true 26226026Sbrianports in the Unix sense. No sockets are actually bound to ports. 26326026SbrianThey are more correctly thought of as placeholders. 26426026Sbrian 26526026SbrianAll packets go through the aliasing mechanism, whether they come from 26626026Sbrianthe gateway machine or other machines on a local area network. 26726026Sbrian*/ 26826026Sbrian 26926026Sbrian 27026026Sbrian/* Local prototypes */ 271127094Sdesstatic int IcmpAliasIn1(struct libalias *, struct ip *); 272127094Sdesstatic int IcmpAliasIn2(struct libalias *, struct ip *); 273127094Sdesstatic int IcmpAliasIn(struct libalias *, struct ip *); 27426026Sbrian 275133719Sphkstatic int IcmpAliasOut1(struct libalias *, struct ip *, int create); 276127094Sdesstatic int IcmpAliasOut2(struct libalias *, struct ip *); 277131566Sphkstatic int IcmpAliasOut(struct libalias *, struct ip *, int create); 27826026Sbrian 279177098Spisostatic int ProtoAliasIn(struct libalias *la, struct in_addr ip_src, 280177098Spiso struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum); 281177098Spisostatic int ProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 282177098Spiso struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, 283177098Spiso int create); 28459726Sru 285127094Sdesstatic int UdpAliasIn(struct libalias *, struct ip *); 286179920Smavstatic int UdpAliasOut(struct libalias *, struct ip *, int, int create); 28726026Sbrian 288127094Sdesstatic int TcpAliasIn(struct libalias *, struct ip *); 289131566Sphkstatic int TcpAliasOut(struct libalias *, struct ip *, int, int create); 29026026Sbrian 29126026Sbrian 29226026Sbrianstatic int 293124621SphkIcmpAliasIn1(struct libalias *la, struct ip *pip) 29426026Sbrian{ 295165243Spiso 296165243Spiso LIBALIAS_LOCK_ASSERT(la); 29726026Sbrian/* 29865280Sru De-alias incoming echo and timestamp replies. 29965280Sru Alias incoming echo and timestamp requests. 30026026Sbrian*/ 301131614Sdes struct alias_link *lnk; 302127094Sdes struct icmp *ic; 30326026Sbrian 304131699Sdes ic = (struct icmp *)ip_next(pip); 30526026Sbrian 30626026Sbrian/* Get source address from ICMP data field and restore original data */ 307131614Sdes lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1); 308131614Sdes if (lnk != NULL) { 309127094Sdes u_short original_id; 310127094Sdes int accumulate; 31126026Sbrian 312131614Sdes original_id = GetOriginalPort(lnk); 31326026Sbrian 31426026Sbrian/* Adjust ICMP checksum */ 315127094Sdes accumulate = ic->icmp_id; 316127094Sdes accumulate -= original_id; 317127094Sdes ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 31826026Sbrian 31926026Sbrian/* Put original sequence number back in */ 320127094Sdes ic->icmp_id = original_id; 32126026Sbrian 32226026Sbrian/* Put original address back into IP header */ 323127094Sdes { 324127094Sdes struct in_addr original_address; 32526026Sbrian 326131614Sdes original_address = GetOriginalAddress(lnk); 327127094Sdes DifferentialChecksum(&pip->ip_sum, 328127689Sdes &original_address, &pip->ip_dst, 2); 329127094Sdes pip->ip_dst = original_address; 330127094Sdes } 33126026Sbrian 332127094Sdes return (PKT_ALIAS_OK); 333127094Sdes } 334127094Sdes return (PKT_ALIAS_IGNORED); 33526026Sbrian} 33626026Sbrian 33726026Sbrianstatic int 338124621SphkIcmpAliasIn2(struct libalias *la, struct ip *pip) 33926026Sbrian{ 340165243Spiso 341165243Spiso LIBALIAS_LOCK_ASSERT(la); 34226026Sbrian/* 34326026Sbrian Alias incoming ICMP error messages containing 34426026Sbrian IP header and first 64 bits of datagram. 34526026Sbrian*/ 346127094Sdes struct ip *ip; 347127094Sdes struct icmp *ic, *ic2; 348127094Sdes struct udphdr *ud; 349127094Sdes struct tcphdr *tc; 350131614Sdes struct alias_link *lnk; 35126026Sbrian 352131699Sdes ic = (struct icmp *)ip_next(pip); 353127094Sdes ip = &ic->icmp_ip; 35426026Sbrian 355131699Sdes ud = (struct udphdr *)ip_next(ip); 356131699Sdes tc = (struct tcphdr *)ip_next(ip); 357131699Sdes ic2 = (struct icmp *)ip_next(ip); 35826026Sbrian 359127094Sdes if (ip->ip_p == IPPROTO_UDP) 360131614Sdes lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src, 361127094Sdes ud->uh_dport, ud->uh_sport, 362127094Sdes IPPROTO_UDP, 0); 363127094Sdes else if (ip->ip_p == IPPROTO_TCP) 364131614Sdes lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src, 365127094Sdes tc->th_dport, tc->th_sport, 366127094Sdes IPPROTO_TCP, 0); 367127094Sdes else if (ip->ip_p == IPPROTO_ICMP) { 368127094Sdes if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) 369131614Sdes lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0); 370127094Sdes else 371131614Sdes lnk = NULL; 372127094Sdes } else 373131614Sdes lnk = NULL; 37426026Sbrian 375131614Sdes if (lnk != NULL) { 376127094Sdes if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) { 377127094Sdes int accumulate, accumulate2; 378127094Sdes struct in_addr original_address; 379127094Sdes u_short original_port; 38026026Sbrian 381131614Sdes original_address = GetOriginalAddress(lnk); 382131614Sdes original_port = GetOriginalPort(lnk); 38399207Sbrian 38426026Sbrian/* Adjust ICMP checksum */ 385127689Sdes accumulate = twowords(&ip->ip_src); 386127689Sdes accumulate -= twowords(&original_address); 387127094Sdes accumulate += ud->uh_sport; 388127094Sdes accumulate -= original_port; 389127094Sdes accumulate2 = accumulate; 390127094Sdes accumulate2 += ip->ip_sum; 391127094Sdes ADJUST_CHECKSUM(accumulate, ip->ip_sum); 392127094Sdes accumulate2 -= ip->ip_sum; 393127094Sdes ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum); 39426026Sbrian 39526026Sbrian/* Un-alias address in IP header */ 396127094Sdes DifferentialChecksum(&pip->ip_sum, 397127689Sdes &original_address, &pip->ip_dst, 2); 398127094Sdes pip->ip_dst = original_address; 39926026Sbrian 40026026Sbrian/* Un-alias address and port number of original IP packet 40126026Sbrianfragment contained in ICMP data section */ 402127094Sdes ip->ip_src = original_address; 403127094Sdes ud->uh_sport = original_port; 404127094Sdes } else if (ip->ip_p == IPPROTO_ICMP) { 405127094Sdes int accumulate, accumulate2; 406127094Sdes struct in_addr original_address; 407127094Sdes u_short original_id; 40826026Sbrian 409131614Sdes original_address = GetOriginalAddress(lnk); 410131614Sdes original_id = GetOriginalPort(lnk); 41126026Sbrian 41226026Sbrian/* Adjust ICMP checksum */ 413127689Sdes accumulate = twowords(&ip->ip_src); 414127689Sdes accumulate -= twowords(&original_address); 415127094Sdes accumulate += ic2->icmp_id; 416127094Sdes accumulate -= original_id; 417127094Sdes accumulate2 = accumulate; 418127094Sdes accumulate2 += ip->ip_sum; 419127094Sdes ADJUST_CHECKSUM(accumulate, ip->ip_sum); 420127094Sdes accumulate2 -= ip->ip_sum; 421127094Sdes ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum); 42226026Sbrian 42326026Sbrian/* Un-alias address in IP header */ 424127094Sdes DifferentialChecksum(&pip->ip_sum, 425127689Sdes &original_address, &pip->ip_dst, 2); 426127094Sdes pip->ip_dst = original_address; 42726026Sbrian 42899207Sbrian/* Un-alias address of original IP packet and sequence number of 42959047Sru embedded ICMP datagram */ 430127094Sdes ip->ip_src = original_address; 431127094Sdes ic2->icmp_id = original_id; 432127094Sdes } 433127094Sdes return (PKT_ALIAS_OK); 434127094Sdes } 435127094Sdes return (PKT_ALIAS_IGNORED); 43626026Sbrian} 43726026Sbrian 43826026Sbrian 43926026Sbrianstatic int 440124621SphkIcmpAliasIn(struct libalias *la, struct ip *pip) 44126026Sbrian{ 442127094Sdes int iresult; 443127094Sdes struct icmp *ic; 44426026Sbrian 445165243Spiso LIBALIAS_LOCK_ASSERT(la); 44644307Sbrian/* Return if proxy-only mode is enabled */ 447127094Sdes if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 448131613Sdes return (PKT_ALIAS_OK); 44944307Sbrian 450131699Sdes ic = (struct icmp *)ip_next(pip); 45126026Sbrian 452127094Sdes iresult = PKT_ALIAS_IGNORED; 453127094Sdes switch (ic->icmp_type) { 454127094Sdes case ICMP_ECHOREPLY: 455127094Sdes case ICMP_TSTAMPREPLY: 456127094Sdes if (ic->icmp_code == 0) { 457127094Sdes iresult = IcmpAliasIn1(la, pip); 458127094Sdes } 459127094Sdes break; 460127094Sdes case ICMP_UNREACH: 461127094Sdes case ICMP_SOURCEQUENCH: 462127094Sdes case ICMP_TIMXCEED: 463127094Sdes case ICMP_PARAMPROB: 464127094Sdes iresult = IcmpAliasIn2(la, pip); 465127094Sdes break; 466127094Sdes case ICMP_ECHO: 467127094Sdes case ICMP_TSTAMP: 468127094Sdes iresult = IcmpAliasIn1(la, pip); 469127094Sdes break; 470127094Sdes } 471127094Sdes return (iresult); 47226026Sbrian} 47326026Sbrian 47426026Sbrian 47526026Sbrianstatic int 476133719SphkIcmpAliasOut1(struct libalias *la, struct ip *pip, int create) 47726026Sbrian{ 47826026Sbrian/* 47965280Sru Alias outgoing echo and timestamp requests. 48065280Sru De-alias outgoing echo and timestamp replies. 48126026Sbrian*/ 482131614Sdes struct alias_link *lnk; 483127094Sdes struct icmp *ic; 48426026Sbrian 485165243Spiso LIBALIAS_LOCK_ASSERT(la); 486131699Sdes ic = (struct icmp *)ip_next(pip); 48726026Sbrian 48826026Sbrian/* Save overwritten data for when echo packet returns */ 489133719Sphk lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create); 490131614Sdes if (lnk != NULL) { 491127094Sdes u_short alias_id; 492127094Sdes int accumulate; 49326026Sbrian 494131614Sdes alias_id = GetAliasPort(lnk); 49526026Sbrian 49626026Sbrian/* Since data field is being modified, adjust ICMP checksum */ 497127094Sdes accumulate = ic->icmp_id; 498127094Sdes accumulate -= alias_id; 499127094Sdes ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 50026026Sbrian 50126026Sbrian/* Alias sequence number */ 502127094Sdes ic->icmp_id = alias_id; 50326026Sbrian 50426026Sbrian/* Change source address */ 505127094Sdes { 506127094Sdes struct in_addr alias_address; 50726026Sbrian 508131614Sdes alias_address = GetAliasAddress(lnk); 509127094Sdes DifferentialChecksum(&pip->ip_sum, 510127689Sdes &alias_address, &pip->ip_src, 2); 511127094Sdes pip->ip_src = alias_address; 512127094Sdes } 51326026Sbrian 514127094Sdes return (PKT_ALIAS_OK); 515127094Sdes } 516127094Sdes return (PKT_ALIAS_IGNORED); 51726026Sbrian} 51826026Sbrian 51926026Sbrian 52026026Sbrianstatic int 521124621SphkIcmpAliasOut2(struct libalias *la, struct ip *pip) 52226026Sbrian{ 52326026Sbrian/* 52426026Sbrian Alias outgoing ICMP error messages containing 52526026Sbrian IP header and first 64 bits of datagram. 52626026Sbrian*/ 527127094Sdes struct ip *ip; 528127094Sdes struct icmp *ic, *ic2; 529127094Sdes struct udphdr *ud; 530127094Sdes struct tcphdr *tc; 531131614Sdes struct alias_link *lnk; 53226026Sbrian 533165243Spiso LIBALIAS_LOCK_ASSERT(la); 534131699Sdes ic = (struct icmp *)ip_next(pip); 535127094Sdes ip = &ic->icmp_ip; 53626026Sbrian 537131699Sdes ud = (struct udphdr *)ip_next(ip); 538131699Sdes tc = (struct tcphdr *)ip_next(ip); 539131699Sdes ic2 = (struct icmp *)ip_next(ip); 54026026Sbrian 541127094Sdes if (ip->ip_p == IPPROTO_UDP) 542131614Sdes lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src, 543127094Sdes ud->uh_dport, ud->uh_sport, 544127094Sdes IPPROTO_UDP, 0); 545127094Sdes else if (ip->ip_p == IPPROTO_TCP) 546131614Sdes lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src, 547127094Sdes tc->th_dport, tc->th_sport, 548127094Sdes IPPROTO_TCP, 0); 549127094Sdes else if (ip->ip_p == IPPROTO_ICMP) { 550127094Sdes if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) 551131614Sdes lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0); 552127094Sdes else 553131614Sdes lnk = NULL; 554127094Sdes } else 555131614Sdes lnk = NULL; 55626026Sbrian 557131614Sdes if (lnk != NULL) { 558127094Sdes if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) { 559127094Sdes int accumulate; 560127094Sdes struct in_addr alias_address; 561127094Sdes u_short alias_port; 56226026Sbrian 563131614Sdes alias_address = GetAliasAddress(lnk); 564131614Sdes alias_port = GetAliasPort(lnk); 56599207Sbrian 56659047Sru/* Adjust ICMP checksum */ 567127689Sdes accumulate = twowords(&ip->ip_dst); 568127689Sdes accumulate -= twowords(&alias_address); 569127094Sdes accumulate += ud->uh_dport; 570127094Sdes accumulate -= alias_port; 571127094Sdes ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 57259047Sru 57365317Sru/* 57465317Sru * Alias address in IP header if it comes from the host 57565317Sru * the original TCP/UDP packet was destined for. 57665317Sru */ 577127094Sdes if (pip->ip_src.s_addr == ip->ip_dst.s_addr) { 578127094Sdes DifferentialChecksum(&pip->ip_sum, 579127689Sdes &alias_address, &pip->ip_src, 2); 580127094Sdes pip->ip_src = alias_address; 581127094Sdes } 58259047Sru/* Alias address and port number of original IP packet 58359047Srufragment contained in ICMP data section */ 584127094Sdes ip->ip_dst = alias_address; 585127094Sdes ud->uh_dport = alias_port; 586127094Sdes } else if (ip->ip_p == IPPROTO_ICMP) { 587127094Sdes int accumulate; 588127094Sdes struct in_addr alias_address; 589127094Sdes u_short alias_id; 59059047Sru 591131614Sdes alias_address = GetAliasAddress(lnk); 592131614Sdes alias_id = GetAliasPort(lnk); 59359047Sru 59459047Sru/* Adjust ICMP checksum */ 595127689Sdes accumulate = twowords(&ip->ip_dst); 596127689Sdes accumulate -= twowords(&alias_address); 597127094Sdes accumulate += ic2->icmp_id; 598127094Sdes accumulate -= alias_id; 599127094Sdes ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 60059047Sru 60165317Sru/* 60265317Sru * Alias address in IP header if it comes from the host 60365317Sru * the original ICMP message was destined for. 60465317Sru */ 605127094Sdes if (pip->ip_src.s_addr == ip->ip_dst.s_addr) { 606127094Sdes DifferentialChecksum(&pip->ip_sum, 607127689Sdes &alias_address, &pip->ip_src, 2); 608127094Sdes pip->ip_src = alias_address; 609127094Sdes } 61099207Sbrian/* Alias address of original IP packet and sequence number of 61159047Sru embedded ICMP datagram */ 612127094Sdes ip->ip_dst = alias_address; 613127094Sdes ic2->icmp_id = alias_id; 614127094Sdes } 615127094Sdes return (PKT_ALIAS_OK); 616127094Sdes } 617127094Sdes return (PKT_ALIAS_IGNORED); 61826026Sbrian} 61926026Sbrian 62026026Sbrian 62126026Sbrianstatic int 622131566SphkIcmpAliasOut(struct libalias *la, struct ip *pip, int create) 62326026Sbrian{ 624127094Sdes int iresult; 625127094Sdes struct icmp *ic; 62626026Sbrian 627165243Spiso LIBALIAS_LOCK_ASSERT(la); 628131614Sdes (void)create; 629131614Sdes 63044307Sbrian/* Return if proxy-only mode is enabled */ 631127094Sdes if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 632131613Sdes return (PKT_ALIAS_OK); 63344307Sbrian 634131699Sdes ic = (struct icmp *)ip_next(pip); 63526026Sbrian 636127094Sdes iresult = PKT_ALIAS_IGNORED; 637127094Sdes switch (ic->icmp_type) { 638127094Sdes case ICMP_ECHO: 639127094Sdes case ICMP_TSTAMP: 640127094Sdes if (ic->icmp_code == 0) { 641133719Sphk iresult = IcmpAliasOut1(la, pip, create); 642127094Sdes } 643127094Sdes break; 644127094Sdes case ICMP_UNREACH: 645127094Sdes case ICMP_SOURCEQUENCH: 646127094Sdes case ICMP_TIMXCEED: 647127094Sdes case ICMP_PARAMPROB: 648127094Sdes iresult = IcmpAliasOut2(la, pip); 649127094Sdes break; 650127094Sdes case ICMP_ECHOREPLY: 651127094Sdes case ICMP_TSTAMPREPLY: 652133719Sphk iresult = IcmpAliasOut1(la, pip, create); 653127094Sdes } 654127094Sdes return (iresult); 65526026Sbrian} 65626026Sbrian 65726026Sbrianstatic int 658177098SpisoProtoAliasIn(struct libalias *la, struct in_addr ip_src, 659177098Spiso struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum) 66044307Sbrian{ 66144307Sbrian/* 66259726Sru Handle incoming IP packets. The 66344307Sbrian only thing which is done in this case is to alias 66444307Sbrian the dest IP address of the packet to our inside 66544307Sbrian machine. 66644307Sbrian*/ 667131614Sdes struct alias_link *lnk; 66844307Sbrian 669165243Spiso LIBALIAS_LOCK_ASSERT(la); 67059356Sru/* Return if proxy-only mode is enabled */ 671127094Sdes if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 672131613Sdes return (PKT_ALIAS_OK); 67344307Sbrian 674177098Spiso lnk = FindProtoIn(la, ip_src, *ip_dst, ip_p); 675131614Sdes if (lnk != NULL) { 676127094Sdes struct in_addr original_address; 67759356Sru 678131614Sdes original_address = GetOriginalAddress(lnk); 67959356Sru 68059356Sru/* Restore original IP address */ 681177098Spiso DifferentialChecksum(ip_sum, 682177098Spiso &original_address, ip_dst, 2); 683177098Spiso *ip_dst = original_address; 68459356Sru 685127094Sdes return (PKT_ALIAS_OK); 686127094Sdes } 687127094Sdes return (PKT_ALIAS_IGNORED); 68844307Sbrian} 68944307Sbrian 69044307Sbrianstatic int 691177098SpisoProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 692177098Spiso struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create) 69344307Sbrian{ 69444307Sbrian/* 69559726Sru Handle outgoing IP packets. The 69644307Sbrian only thing which is done in this case is to alias 69744307Sbrian the source IP address of the packet. 69844307Sbrian*/ 699131614Sdes struct alias_link *lnk; 70044307Sbrian 701165243Spiso LIBALIAS_LOCK_ASSERT(la); 702131614Sdes (void)create; 703131614Sdes 70459356Sru/* Return if proxy-only mode is enabled */ 705127094Sdes if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 706131613Sdes return (PKT_ALIAS_OK); 70744307Sbrian 708177098Spiso lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p); 709131614Sdes if (lnk != NULL) { 710127094Sdes struct in_addr alias_address; 71159356Sru 712131614Sdes alias_address = GetAliasAddress(lnk); 71359356Sru 71459356Sru/* Change source address */ 715177098Spiso DifferentialChecksum(ip_sum, 716177098Spiso &alias_address, ip_src, 2); 717177098Spiso *ip_src = alias_address; 71859356Sru 719127094Sdes return (PKT_ALIAS_OK); 720127094Sdes } 721127094Sdes return (PKT_ALIAS_IGNORED); 72244307Sbrian} 72344307Sbrian 72444307Sbrian 72561861Srustatic int 726124621SphkUdpAliasIn(struct libalias *la, struct ip *pip) 72726026Sbrian{ 728127094Sdes struct udphdr *ud; 729131614Sdes struct alias_link *lnk; 73026026Sbrian 731165243Spiso LIBALIAS_LOCK_ASSERT(la); 73244307Sbrian 733131699Sdes ud = (struct udphdr *)ip_next(pip); 73426026Sbrian 735131614Sdes lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 736127094Sdes ud->uh_sport, ud->uh_dport, 737179920Smav IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 738131614Sdes if (lnk != NULL) { 739127094Sdes struct in_addr alias_address; 740127094Sdes struct in_addr original_address; 741179920Smav struct in_addr proxy_address; 742127094Sdes u_short alias_port; 743179920Smav u_short proxy_port; 744127094Sdes int accumulate; 745190938Spiso int error; 746162674Spiso struct alias_data ad = { 747162674Spiso .lnk = lnk, 748162674Spiso .oaddr = &original_address, 749162674Spiso .aaddr = &alias_address, 750162674Spiso .aport = &alias_port, 751162674Spiso .sport = &ud->uh_sport, 752162674Spiso .dport = &ud->uh_dport, 753162674Spiso .maxpktsize = 0 754162674Spiso }; 75526026Sbrian 756131614Sdes alias_address = GetAliasAddress(lnk); 757131614Sdes original_address = GetOriginalAddress(lnk); 758179920Smav proxy_address = GetProxyAddress(lnk); 759127094Sdes alias_port = ud->uh_dport; 760131614Sdes ud->uh_dport = GetOriginalPort(lnk); 761179920Smav proxy_port = GetProxyPort(lnk); 76226026Sbrian 763162674Spiso /* Walk out chain. */ 764162674Spiso error = find_handler(IN, UDP, la, pip, &ad); 765190941Spiso /* If we cannot figure out the packet, ignore it. */ 766190941Spiso if (error < 0) 767190941Spiso return (PKT_ALIAS_IGNORED); 76836321Samurai 76926026Sbrian/* If UDP checksum is not zero, then adjust since destination port */ 77066545Sru/* is being unaliased and destination address is being altered. */ 771127094Sdes if (ud->uh_sum != 0) { 772127094Sdes accumulate = alias_port; 773127094Sdes accumulate -= ud->uh_dport; 774127689Sdes accumulate += twowords(&alias_address); 775127689Sdes accumulate -= twowords(&original_address); 776179920Smav 777179920Smav/* If this is a proxy packet, modify checksum because of source change.*/ 778179920Smav if (proxy_port != 0) { 779179920Smav accumulate += ud->uh_sport; 780179920Smav accumulate -= proxy_port; 781179920Smav } 782179920Smav 783179920Smav if (proxy_address.s_addr != 0) { 784179920Smav accumulate += twowords(&pip->ip_src); 785179920Smav accumulate -= twowords(&proxy_address); 786179920Smav } 787179920Smav 788127094Sdes ADJUST_CHECKSUM(accumulate, ud->uh_sum); 789127094Sdes } 790179920Smav/* XXX: Could the two if's below be concatenated to one ? */ 791179920Smav/* Restore source port and/or address in case of proxying*/ 792179920Smav 793179920Smav if (proxy_port != 0) 794179920Smav ud->uh_sport = proxy_port; 795179920Smav 796179920Smav if (proxy_address.s_addr != 0) { 797179920Smav DifferentialChecksum(&pip->ip_sum, 798179920Smav &proxy_address, &pip->ip_src, 2); 799179920Smav pip->ip_src = proxy_address; 800179920Smav } 801179920Smav 80226026Sbrian/* Restore original IP address */ 803127094Sdes DifferentialChecksum(&pip->ip_sum, 804127689Sdes &original_address, &pip->ip_dst, 2); 805127094Sdes pip->ip_dst = original_address; 80641759Sdillon 807190941Spiso return (PKT_ALIAS_OK); 808127094Sdes } 809127094Sdes return (PKT_ALIAS_IGNORED); 81026026Sbrian} 81126026Sbrian 81226026Sbrianstatic int 813179920SmavUdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 81426026Sbrian{ 815127094Sdes struct udphdr *ud; 816131614Sdes struct alias_link *lnk; 817179920Smav struct in_addr dest_address; 818179920Smav struct in_addr proxy_server_address; 819179920Smav u_short dest_port; 820179920Smav u_short proxy_server_port; 821179920Smav int proxy_type; 822162674Spiso int error; 82326026Sbrian 824165243Spiso LIBALIAS_LOCK_ASSERT(la); 82544307Sbrian 826179920Smav/* Return if proxy-only mode is enabled and not proxyrule found.*/ 827131699Sdes ud = (struct udphdr *)ip_next(pip); 828179920Smav proxy_type = ProxyCheck(la, &proxy_server_address, 829179920Smav &proxy_server_port, pip->ip_src, pip->ip_dst, 830179920Smav ud->uh_dport, pip->ip_p); 831179920Smav if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 832179920Smav return (PKT_ALIAS_OK); 83326026Sbrian 834179920Smav/* If this is a transparent proxy, save original destination, 835179920Smav * then alter the destination and adjust checksums */ 836179920Smav dest_port = ud->uh_dport; 837179920Smav dest_address = pip->ip_dst; 838179920Smav 839179920Smav if (proxy_type != 0) { 840179920Smav int accumulate; 841179920Smav 842179920Smav accumulate = twowords(&pip->ip_dst); 843179920Smav accumulate -= twowords(&proxy_server_address); 844179920Smav 845179920Smav ADJUST_CHECKSUM(accumulate, pip->ip_sum); 846179920Smav 847179920Smav if (ud->uh_sum != 0) { 848179920Smav accumulate = twowords(&pip->ip_dst); 849179920Smav accumulate -= twowords(&proxy_server_address); 850179920Smav accumulate += ud->uh_dport; 851179920Smav accumulate -= proxy_server_port; 852179920Smav ADJUST_CHECKSUM(accumulate, ud->uh_sum); 853179920Smav } 854179920Smav pip->ip_dst = proxy_server_address; 855179920Smav ud->uh_dport = proxy_server_port; 856179920Smav } 857131614Sdes lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 858127094Sdes ud->uh_sport, ud->uh_dport, 859131566Sphk IPPROTO_UDP, create); 860131614Sdes if (lnk != NULL) { 861127094Sdes u_short alias_port; 862127094Sdes struct in_addr alias_address; 863162674Spiso struct alias_data ad = { 864162674Spiso .lnk = lnk, 865162674Spiso .oaddr = NULL, 866162674Spiso .aaddr = &alias_address, 867162674Spiso .aport = &alias_port, 868162674Spiso .sport = &ud->uh_sport, 869162674Spiso .dport = &ud->uh_dport, 870162674Spiso .maxpktsize = 0 871162674Spiso }; 87226026Sbrian 873179920Smav/* Save original destination address, if this is a proxy packet. 874179920Smav * Also modify packet to include destination encoding. This may 875179920Smav * change the size of IP header. */ 876179920Smav if (proxy_type != 0) { 877179920Smav SetProxyPort(lnk, dest_port); 878179920Smav SetProxyAddress(lnk, dest_address); 879179920Smav ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 880179920Smav ud = (struct udphdr *)ip_next(pip); 881179920Smav } 882179920Smav 883131614Sdes alias_address = GetAliasAddress(lnk); 884131614Sdes alias_port = GetAliasPort(lnk); 88526026Sbrian 886162674Spiso /* Walk out chain. */ 887162674Spiso error = find_handler(OUT, UDP, la, pip, &ad); 88836321Samurai 88926026Sbrian/* If UDP checksum is not zero, adjust since source port is */ 89026026Sbrian/* being aliased and source address is being altered */ 891127094Sdes if (ud->uh_sum != 0) { 892127094Sdes int accumulate; 89326026Sbrian 894127094Sdes accumulate = ud->uh_sport; 895127094Sdes accumulate -= alias_port; 896127689Sdes accumulate += twowords(&pip->ip_src); 897127689Sdes accumulate -= twowords(&alias_address); 898127094Sdes ADJUST_CHECKSUM(accumulate, ud->uh_sum); 899127094Sdes } 90036321Samurai/* Put alias port in UDP header */ 901127094Sdes ud->uh_sport = alias_port; 90226026Sbrian 90326026Sbrian/* Change source address */ 904127094Sdes DifferentialChecksum(&pip->ip_sum, 905127689Sdes &alias_address, &pip->ip_src, 2); 906127094Sdes pip->ip_src = alias_address; 90726026Sbrian 908127094Sdes return (PKT_ALIAS_OK); 909127094Sdes } 910127094Sdes return (PKT_ALIAS_IGNORED); 91126026Sbrian} 91226026Sbrian 91326026Sbrian 91426026Sbrian 91526026Sbrianstatic int 916124621SphkTcpAliasIn(struct libalias *la, struct ip *pip) 91726026Sbrian{ 918127094Sdes struct tcphdr *tc; 919131614Sdes struct alias_link *lnk; 92026026Sbrian 921165243Spiso LIBALIAS_LOCK_ASSERT(la); 922131699Sdes tc = (struct tcphdr *)ip_next(pip); 92326026Sbrian 924131614Sdes lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 925127094Sdes tc->th_sport, tc->th_dport, 926127094Sdes IPPROTO_TCP, 927127094Sdes !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 928131614Sdes if (lnk != NULL) { 929127094Sdes struct in_addr alias_address; 930127094Sdes struct in_addr original_address; 931127094Sdes struct in_addr proxy_address; 932127094Sdes u_short alias_port; 933127094Sdes u_short proxy_port; 934162674Spiso int accumulate, error; 93526026Sbrian 936162674Spiso /* 937162674Spiso * The init of MANY vars is a bit below, but aliashandlepptpin 938162674Spiso * seems to need the destination port that came within the 939162674Spiso * packet and not the original one looks below [*]. 940162674Spiso */ 94161861Sru 942162674Spiso struct alias_data ad = { 943162674Spiso .lnk = lnk, 944162674Spiso .oaddr = NULL, 945162674Spiso .aaddr = NULL, 946162674Spiso .aport = NULL, 947162674Spiso .sport = &tc->th_sport, 948162674Spiso .dport = &tc->th_dport, 949162674Spiso .maxpktsize = 0 950162674Spiso }; 951162674Spiso 952162674Spiso /* Walk out chain. */ 953162674Spiso error = find_handler(IN, TCP, la, pip, &ad); 954162674Spiso 955131614Sdes alias_address = GetAliasAddress(lnk); 956131614Sdes original_address = GetOriginalAddress(lnk); 957131614Sdes proxy_address = GetProxyAddress(lnk); 958127094Sdes alias_port = tc->th_dport; 959131614Sdes tc->th_dport = GetOriginalPort(lnk); 960131614Sdes proxy_port = GetProxyPort(lnk); 96126026Sbrian 962162674Spiso /* 963162674Spiso * Look above, if anyone is going to add find_handler AFTER 964162674Spiso * this aliashandlepptpin/point, please redo alias_data too. 965162674Spiso * Uncommenting the piece here below should be enough. 966162674Spiso */ 967162674Spiso#if 0 968162674Spiso struct alias_data ad = { 969162674Spiso .lnk = lnk, 970162674Spiso .oaddr = &original_address, 971162674Spiso .aaddr = &alias_address, 972162674Spiso .aport = &alias_port, 973162674Spiso .sport = &ud->uh_sport, 974162674Spiso .dport = &ud->uh_dport, 975162674Spiso .maxpktsize = 0 976162674Spiso }; 977162674Spiso 978162674Spiso /* Walk out chain. */ 979162674Spiso error = find_handler(la, pip, &ad); 980162674Spiso if (error == EHDNOF) 981162674Spiso printf("Protocol handler not found\n"); 982162674Spiso#endif 983162674Spiso 98426026Sbrian/* Adjust TCP checksum since destination port is being unaliased */ 98526026Sbrian/* and destination port is being altered. */ 986127094Sdes accumulate = alias_port; 987127094Sdes accumulate -= tc->th_dport; 988127689Sdes accumulate += twowords(&alias_address); 989127689Sdes accumulate -= twowords(&original_address); 99026026Sbrian 99159356Sru/* If this is a proxy, then modify the TCP source port and 99244307Sbrian checksum accumulation */ 993127094Sdes if (proxy_port != 0) { 994127094Sdes accumulate += tc->th_sport; 995127094Sdes tc->th_sport = proxy_port; 996127094Sdes accumulate -= tc->th_sport; 997127689Sdes accumulate += twowords(&pip->ip_src); 998127689Sdes accumulate -= twowords(&proxy_address); 999127094Sdes } 100059356Sru/* See if ACK number needs to be modified */ 1001131614Sdes if (GetAckModified(lnk) == 1) { 1002127094Sdes int delta; 100326026Sbrian 1004176884Spiso tc = (struct tcphdr *)ip_next(pip); 1005176884Spiso delta = GetDeltaAckIn(tc->th_ack, lnk); 1006127094Sdes if (delta != 0) { 1007127689Sdes accumulate += twowords(&tc->th_ack); 1008127094Sdes tc->th_ack = htonl(ntohl(tc->th_ack) - delta); 1009127689Sdes accumulate -= twowords(&tc->th_ack); 1010127094Sdes } 1011127094Sdes } 1012127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 101326026Sbrian 101426026Sbrian/* Restore original IP address */ 1015127689Sdes accumulate = twowords(&pip->ip_dst); 1016127757Sdeischen pip->ip_dst = original_address; 1017127689Sdes accumulate -= twowords(&pip->ip_dst); 101826026Sbrian 101944307Sbrian/* If this is a transparent proxy packet, then modify the source 102044307Sbrian address */ 1021127094Sdes if (proxy_address.s_addr != 0) { 1022127689Sdes accumulate += twowords(&pip->ip_src); 1023127094Sdes pip->ip_src = proxy_address; 1024127689Sdes accumulate -= twowords(&pip->ip_src); 1025127094Sdes } 1026127094Sdes ADJUST_CHECKSUM(accumulate, pip->ip_sum); 102744307Sbrian 102826026Sbrian/* Monitor TCP connection state */ 1029176884Spiso tc = (struct tcphdr *)ip_next(pip); 1030176884Spiso TcpMonitorIn(tc->th_flags, lnk); 103126026Sbrian 1032127094Sdes return (PKT_ALIAS_OK); 1033127094Sdes } 1034127094Sdes return (PKT_ALIAS_IGNORED); 103526026Sbrian} 103626026Sbrian 103726026Sbrianstatic int 1038131566SphkTcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 103926026Sbrian{ 1040162674Spiso int proxy_type, error; 1041127094Sdes u_short dest_port; 1042127094Sdes u_short proxy_server_port; 1043127094Sdes struct in_addr dest_address; 1044127094Sdes struct in_addr proxy_server_address; 1045127094Sdes struct tcphdr *tc; 1046131614Sdes struct alias_link *lnk; 104726026Sbrian 1048165243Spiso LIBALIAS_LOCK_ASSERT(la); 1049131699Sdes tc = (struct tcphdr *)ip_next(pip); 105026026Sbrian 1051147636Sphk if (create) 1052176884Spiso proxy_type = ProxyCheck(la, &proxy_server_address, 1053176884Spiso &proxy_server_port, pip->ip_src, pip->ip_dst, 1054176884Spiso tc->th_dport, pip->ip_p); 1055147636Sphk else 1056147636Sphk proxy_type = 0; 105744307Sbrian 1058127094Sdes if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 1059131613Sdes return (PKT_ALIAS_OK); 106044307Sbrian 106144307Sbrian/* If this is a transparent proxy, save original destination, 106259356Sru then alter the destination and adjust checksums */ 1063127094Sdes dest_port = tc->th_dport; 1064127094Sdes dest_address = pip->ip_dst; 1065127094Sdes if (proxy_type != 0) { 1066127094Sdes int accumulate; 106744307Sbrian 1068127094Sdes accumulate = tc->th_dport; 1069127094Sdes tc->th_dport = proxy_server_port; 1070127094Sdes accumulate -= tc->th_dport; 1071127689Sdes accumulate += twowords(&pip->ip_dst); 1072127689Sdes accumulate -= twowords(&proxy_server_address); 1073127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 107444307Sbrian 1075127689Sdes accumulate = twowords(&pip->ip_dst); 1076127094Sdes pip->ip_dst = proxy_server_address; 1077127689Sdes accumulate -= twowords(&pip->ip_dst); 1078127094Sdes ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1079127094Sdes } 1080131614Sdes lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 1081127094Sdes tc->th_sport, tc->th_dport, 1082131566Sphk IPPROTO_TCP, create); 1083131614Sdes if (lnk == NULL) 1084131566Sphk return (PKT_ALIAS_IGNORED); 1085131614Sdes if (lnk != NULL) { 1086127094Sdes u_short alias_port; 1087127094Sdes struct in_addr alias_address; 1088127094Sdes int accumulate; 1089162674Spiso struct alias_data ad = { 1090162674Spiso .lnk = lnk, 1091162674Spiso .oaddr = NULL, 1092162674Spiso .aaddr = &alias_address, 1093162674Spiso .aport = &alias_port, 1094162674Spiso .sport = &tc->th_sport, 1095162674Spiso .dport = &tc->th_dport, 1096162674Spiso .maxpktsize = maxpacketsize 1097162674Spiso }; 109844307Sbrian 109944307Sbrian/* Save original destination address, if this is a proxy packet. 110088132Sru Also modify packet to include destination encoding. This may 110188132Sru change the size of IP header. */ 1102127094Sdes if (proxy_type != 0) { 1103131614Sdes SetProxyPort(lnk, dest_port); 1104131614Sdes SetProxyAddress(lnk, dest_address); 1105131614Sdes ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 1106131699Sdes tc = (struct tcphdr *)ip_next(pip); 1107127094Sdes } 110844307Sbrian/* Get alias address and port */ 1109131614Sdes alias_port = GetAliasPort(lnk); 1110131614Sdes alias_address = GetAliasAddress(lnk); 111126026Sbrian 111259356Sru/* Monitor TCP connection state */ 1113176884Spiso tc = (struct tcphdr *)ip_next(pip); 1114176884Spiso TcpMonitorOut(tc->th_flags, lnk); 1115162674Spiso 1116162674Spiso /* Walk out chain. */ 1117162674Spiso error = find_handler(OUT, TCP, la, pip, &ad); 111826026Sbrian 111926026Sbrian/* Adjust TCP checksum since source port is being aliased */ 112026026Sbrian/* and source address is being altered */ 1121127094Sdes accumulate = tc->th_sport; 1122127094Sdes tc->th_sport = alias_port; 1123127094Sdes accumulate -= tc->th_sport; 1124127689Sdes accumulate += twowords(&pip->ip_src); 1125127689Sdes accumulate -= twowords(&alias_address); 112644307Sbrian 112726026Sbrian/* Modify sequence number if necessary */ 1128131614Sdes if (GetAckModified(lnk) == 1) { 1129127094Sdes int delta; 1130176884Spiso 1131176884Spiso tc = (struct tcphdr *)ip_next(pip); 1132176884Spiso delta = GetDeltaSeqOut(tc->th_seq, lnk); 1133127094Sdes if (delta != 0) { 1134127689Sdes accumulate += twowords(&tc->th_seq); 1135127094Sdes tc->th_seq = htonl(ntohl(tc->th_seq) + delta); 1136127689Sdes accumulate -= twowords(&tc->th_seq); 1137127094Sdes } 1138127094Sdes } 1139127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 114026026Sbrian 114126026Sbrian/* Change source address */ 1142127689Sdes accumulate = twowords(&pip->ip_src); 1143127094Sdes pip->ip_src = alias_address; 1144127689Sdes accumulate -= twowords(&pip->ip_src); 1145127094Sdes ADJUST_CHECKSUM(accumulate, pip->ip_sum); 114644307Sbrian 1147127094Sdes return (PKT_ALIAS_OK); 1148127094Sdes } 1149127094Sdes return (PKT_ALIAS_IGNORED); 115026026Sbrian} 115126026Sbrian 115226026Sbrian 115326026Sbrian 115426026Sbrian 115526026Sbrian/* Fragment Handling 115626026Sbrian 115726026Sbrian FragmentIn() 115826026Sbrian FragmentOut() 115926026Sbrian 116026026SbrianThe packet aliasing module has a limited ability for handling IP 116126026Sbrianfragments. If the ICMP, TCP or UDP header is in the first fragment 116259356Srureceived, then the ID number of the IP packet is saved, and other 116326026Sbrianfragments are identified according to their ID number and IP address 116426026Sbrianthey were sent from. Pointers to unresolved fragments can also be 116526026Sbriansaved and recalled when a header fragment is seen. 116626026Sbrian*/ 116726026Sbrian 116826026Sbrian/* Local prototypes */ 1169177098Spisostatic int FragmentIn(struct libalias *la, struct in_addr ip_src, 1170179472Smav struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum); 1171177098Spisostatic int FragmentOut(struct libalias *, struct in_addr *ip_src, 1172177098Spiso u_short *ip_sum); 117326026Sbrian 117426026Sbrianstatic int 1175177098SpisoFragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst, 1176179472Smav u_short ip_id, u_short *ip_sum) 117726026Sbrian{ 1178131614Sdes struct alias_link *lnk; 117926026Sbrian 1180165243Spiso LIBALIAS_LOCK_ASSERT(la); 1181177098Spiso lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id); 1182131614Sdes if (lnk != NULL) { 1183127094Sdes struct in_addr original_address; 118426026Sbrian 1185131614Sdes GetFragmentAddr(lnk, &original_address); 1186177098Spiso DifferentialChecksum(ip_sum, 1187177098Spiso &original_address, ip_dst, 2); 1188177098Spiso *ip_dst = original_address; 118999207Sbrian 1190127094Sdes return (PKT_ALIAS_OK); 1191127094Sdes } 1192127094Sdes return (PKT_ALIAS_UNRESOLVED_FRAGMENT); 119326026Sbrian} 119426026Sbrian 119526026Sbrianstatic int 1196177098SpisoFragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum) 119726026Sbrian{ 1198127094Sdes struct in_addr alias_address; 119926026Sbrian 1200165243Spiso LIBALIAS_LOCK_ASSERT(la); 1201177098Spiso alias_address = FindAliasAddress(la, *ip_src); 1202177098Spiso DifferentialChecksum(ip_sum, 1203177098Spiso &alias_address, ip_src, 2); 1204177098Spiso *ip_src = alias_address; 120526026Sbrian 1206127094Sdes return (PKT_ALIAS_OK); 120726026Sbrian} 120826026Sbrian 120926026Sbrian 121026026Sbrian 121126026Sbrian 121226026Sbrian 121326026Sbrian 121426026Sbrian/* Outside World Access 121526026Sbrian 1216131612Sdes PacketAliasSaveFragment() 1217131612Sdes PacketAliasGetFragment() 1218131612Sdes PacketAliasFragmentIn() 1219131612Sdes PacketAliasIn() 1220131612Sdes PacketAliasOut() 1221131612Sdes PacketUnaliasOut() 122226026Sbrian 122326026Sbrian(prototypes in alias.h) 122426026Sbrian*/ 122526026Sbrian 122626026Sbrianint 1227124621SphkLibAliasSaveFragment(struct libalias *la, char *ptr) 122826026Sbrian{ 1229127094Sdes int iresult; 1230131614Sdes struct alias_link *lnk; 1231127094Sdes struct ip *pip; 123226026Sbrian 1233165243Spiso LIBALIAS_LOCK(la); 1234127094Sdes pip = (struct ip *)ptr; 1235131614Sdes lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id); 1236127094Sdes iresult = PKT_ALIAS_ERROR; 1237131614Sdes if (lnk != NULL) { 1238131614Sdes SetFragmentPtr(lnk, ptr); 1239127094Sdes iresult = PKT_ALIAS_OK; 1240127094Sdes } 1241165243Spiso LIBALIAS_UNLOCK(la); 1242127094Sdes return (iresult); 124326026Sbrian} 124426026Sbrian 1245127094Sdeschar * 1246124621SphkLibAliasGetFragment(struct libalias *la, char *ptr) 124726026Sbrian{ 1248131614Sdes struct alias_link *lnk; 1249127094Sdes char *fptr; 1250127094Sdes struct ip *pip; 125126026Sbrian 1252165243Spiso LIBALIAS_LOCK(la); 1253127094Sdes pip = (struct ip *)ptr; 1254131614Sdes lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id); 1255131614Sdes if (lnk != NULL) { 1256131614Sdes GetFragmentPtr(lnk, &fptr); 1257131614Sdes SetFragmentPtr(lnk, NULL); 1258131614Sdes SetExpire(lnk, 0); /* Deletes link */ 1259165243Spiso } else 1260165243Spiso fptr = NULL; 126126026Sbrian 1262165243Spiso LIBALIAS_UNLOCK(la); 1263165243Spiso return (fptr); 126426026Sbrian} 126526026Sbrian 126626026Sbrianvoid 1267127094SdesLibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly 1268127094Sdes * de-aliased header 1269127094Sdes * fragment */ 1270127094Sdes char *ptr_fragment /* Points to fragment which must be 1271127094Sdes * de-aliased */ 1272127094Sdes) 127326026Sbrian{ 1274127094Sdes struct ip *pip; 1275127094Sdes struct ip *fpip; 127626026Sbrian 1277165243Spiso LIBALIAS_LOCK(la); 1278131614Sdes (void)la; 1279127094Sdes pip = (struct ip *)ptr; 1280127094Sdes fpip = (struct ip *)ptr_fragment; 128126026Sbrian 1282127094Sdes DifferentialChecksum(&fpip->ip_sum, 1283127689Sdes &pip->ip_dst, &fpip->ip_dst, 2); 1284127094Sdes fpip->ip_dst = pip->ip_dst; 1285165243Spiso LIBALIAS_UNLOCK(la); 128626026Sbrian} 128726026Sbrian 1288165243Spiso/* Local prototypes */ 1289165243Spisostatic int 1290165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr, 1291165243Spiso int maxpacketsize, int create); 1292165243Spisostatic int 1293165243SpisoLibAliasInLocked(struct libalias *la, char *ptr, 1294165243Spiso int maxpacketsize); 129526026Sbrian 129626026Sbrianint 1297124621SphkLibAliasIn(struct libalias *la, char *ptr, int maxpacketsize) 129826026Sbrian{ 1299165243Spiso int res; 1300165243Spiso 1301165243Spiso LIBALIAS_LOCK(la); 1302165243Spiso res = LibAliasInLocked(la, ptr, maxpacketsize); 1303165243Spiso LIBALIAS_UNLOCK(la); 1304165243Spiso return (res); 1305165243Spiso} 1306165243Spiso 1307165243Spisostatic int 1308165243SpisoLibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) 1309165243Spiso{ 1310127094Sdes struct in_addr alias_addr; 1311127094Sdes struct ip *pip; 1312127094Sdes int iresult; 131326026Sbrian 1314127094Sdes if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1315127094Sdes la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1316165243Spiso iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1317127094Sdes la->packetAliasMode |= PKT_ALIAS_REVERSE; 1318165243Spiso goto getout; 1319127094Sdes } 1320127094Sdes HouseKeeping(la); 1321127094Sdes ClearCheckNewLink(la); 1322127094Sdes pip = (struct ip *)ptr; 1323127094Sdes alias_addr = pip->ip_dst; 132444307Sbrian 1325127094Sdes /* Defense against mangled packets */ 1326127094Sdes if (ntohs(pip->ip_len) > maxpacketsize 1327165243Spiso || (pip->ip_hl << 2) > maxpacketsize) { 1328165243Spiso iresult = PKT_ALIAS_IGNORED; 1329165243Spiso goto getout; 1330165243Spiso } 133199207Sbrian 1332127094Sdes iresult = PKT_ALIAS_IGNORED; 1333127094Sdes if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1334127094Sdes switch (pip->ip_p) { 1335127094Sdes case IPPROTO_ICMP: 1336127094Sdes iresult = IcmpAliasIn(la, pip); 1337127094Sdes break; 1338127094Sdes case IPPROTO_UDP: 1339127094Sdes iresult = UdpAliasIn(la, pip); 1340127094Sdes break; 1341127094Sdes case IPPROTO_TCP: 1342127094Sdes iresult = TcpAliasIn(la, pip); 1343127094Sdes break; 1344188294Spiso#ifdef _KERNEL 1345188294Spiso case IPPROTO_SCTP: 1346188294Spiso iresult = SctpAlias(la, pip, SN_TO_LOCAL); 1347188294Spiso break; 1348188294Spiso#endif 1349162674Spiso case IPPROTO_GRE: { 1350162674Spiso int error; 1351162674Spiso struct alias_data ad = { 1352162674Spiso .lnk = NULL, 1353162674Spiso .oaddr = NULL, 1354162674Spiso .aaddr = NULL, 1355162674Spiso .aport = NULL, 1356162674Spiso .sport = NULL, 1357162674Spiso .dport = NULL, 1358162674Spiso .maxpktsize = 0 1359162674Spiso }; 1360162674Spiso 1361162674Spiso /* Walk out chain. */ 1362162674Spiso error = find_handler(IN, IP, la, pip, &ad); 1363162674Spiso if (error == 0) 1364127094Sdes iresult = PKT_ALIAS_OK; 1365127094Sdes else 1366177098Spiso iresult = ProtoAliasIn(la, pip->ip_src, 1367177098Spiso &pip->ip_dst, pip->ip_p, &pip->ip_sum); 1368162674Spiso } 1369162674Spiso break; 1370127094Sdes default: 1371177098Spiso iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst, 1372177098Spiso pip->ip_p, &pip->ip_sum); 1373127094Sdes break; 1374127094Sdes } 137599207Sbrian 1376127094Sdes if (ntohs(pip->ip_off) & IP_MF) { 1377131614Sdes struct alias_link *lnk; 137826026Sbrian 1379131614Sdes lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id); 1380131614Sdes if (lnk != NULL) { 1381127094Sdes iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; 1382131614Sdes SetFragmentAddr(lnk, pip->ip_dst); 1383127094Sdes } else { 1384127094Sdes iresult = PKT_ALIAS_ERROR; 1385127094Sdes } 1386127094Sdes } 1387127094Sdes } else { 1388177098Spiso iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id, 1389177098Spiso &pip->ip_sum); 1390127094Sdes } 139126026Sbrian 1392165243Spisogetout: 1393127094Sdes return (iresult); 139426026Sbrian} 139526026Sbrian 139626026Sbrian 139726026Sbrian 139826026Sbrian/* Unregistered address ranges */ 139926026Sbrian 140026026Sbrian/* 10.0.0.0 -> 10.255.255.255 */ 140126026Sbrian#define UNREG_ADDR_A_LOWER 0x0a000000 140226026Sbrian#define UNREG_ADDR_A_UPPER 0x0affffff 140326026Sbrian 140426026Sbrian/* 172.16.0.0 -> 172.31.255.255 */ 140526026Sbrian#define UNREG_ADDR_B_LOWER 0xac100000 140626026Sbrian#define UNREG_ADDR_B_UPPER 0xac1fffff 140726026Sbrian 140826026Sbrian/* 192.168.0.0 -> 192.168.255.255 */ 140926026Sbrian#define UNREG_ADDR_C_LOWER 0xc0a80000 141026026Sbrian#define UNREG_ADDR_C_UPPER 0xc0a8ffff 141126026Sbrian 141226026Sbrianint 1413165243SpisoLibAliasOut(struct libalias *la, char *ptr, int maxpacketsize) 141426026Sbrian{ 1415165243Spiso int res; 1416165243Spiso 1417165243Spiso LIBALIAS_LOCK(la); 1418165243Spiso res = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1419165243Spiso LIBALIAS_UNLOCK(la); 1420165243Spiso return (res); 1421131566Sphk} 1422131566Sphk 1423131566Sphkint 1424165243SpisoLibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create) 1425165243Spiso{ 1426165243Spiso int res; 1427165243Spiso 1428165243Spiso LIBALIAS_LOCK(la); 1429165243Spiso res = LibAliasOutLocked(la, ptr, maxpacketsize, create); 1430165243Spiso LIBALIAS_UNLOCK(la); 1431165243Spiso return (res); 1432165243Spiso} 1433165243Spiso 1434165243Spisostatic int 1435165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ 1436131566Sphk int maxpacketsize, /* How much the packet data may grow (FTP 1437131566Sphk * and IRC inline changes) */ 1438165243Spiso int create /* Create new entries ? */ 1439131566Sphk) 1440131566Sphk{ 1441127094Sdes int iresult; 1442127094Sdes struct in_addr addr_save; 1443127094Sdes struct ip *pip; 144426026Sbrian 1445127094Sdes if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1446127094Sdes la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1447165243Spiso iresult = LibAliasInLocked(la, ptr, maxpacketsize); 1448127094Sdes la->packetAliasMode |= PKT_ALIAS_REVERSE; 1449165243Spiso goto getout; 1450127094Sdes } 1451127094Sdes HouseKeeping(la); 1452127094Sdes ClearCheckNewLink(la); 1453127094Sdes pip = (struct ip *)ptr; 145444307Sbrian 1455127094Sdes /* Defense against mangled packets */ 1456127094Sdes if (ntohs(pip->ip_len) > maxpacketsize 1457165243Spiso || (pip->ip_hl << 2) > maxpacketsize) { 1458165243Spiso iresult = PKT_ALIAS_IGNORED; 1459165243Spiso goto getout; 1460165243Spiso } 146126026Sbrian 1462127094Sdes addr_save = GetDefaultAliasAddress(la); 1463127094Sdes if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) { 1464127094Sdes u_long addr; 1465127094Sdes int iclass; 146632377Seivind 1467127094Sdes iclass = 0; 1468127094Sdes addr = ntohl(pip->ip_src.s_addr); 1469127094Sdes if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) 1470127094Sdes iclass = 3; 1471127094Sdes else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) 1472127094Sdes iclass = 2; 1473127094Sdes else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) 1474127094Sdes iclass = 1; 147526026Sbrian 1476127094Sdes if (iclass == 0) { 1477127094Sdes SetDefaultAliasAddress(la, pip->ip_src); 1478127094Sdes } 1479127094Sdes } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) { 1480127094Sdes SetDefaultAliasAddress(la, pip->ip_src); 1481127094Sdes } 1482127094Sdes iresult = PKT_ALIAS_IGNORED; 1483127094Sdes if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1484127094Sdes switch (pip->ip_p) { 1485127094Sdes case IPPROTO_ICMP: 1486131566Sphk iresult = IcmpAliasOut(la, pip, create); 1487127094Sdes break; 1488127094Sdes case IPPROTO_UDP: 1489179920Smav iresult = UdpAliasOut(la, pip, maxpacketsize, create); 1490127094Sdes break; 1491188294Spiso case IPPROTO_TCP: 1492131566Sphk iresult = TcpAliasOut(la, pip, maxpacketsize, create); 1493127094Sdes break; 1494188294Spiso#ifdef _KERNEL 1495188294Spiso case IPPROTO_SCTP: 1496188294Spiso iresult = SctpAlias(la, pip, SN_TO_GLOBAL); 1497188294Spiso break; 1498188294Spiso#endif 1499188294Spiso case IPPROTO_GRE: { 1500162674Spiso int error; 1501162674Spiso struct alias_data ad = { 1502162674Spiso .lnk = NULL, 1503162674Spiso .oaddr = NULL, 1504162674Spiso .aaddr = NULL, 1505162674Spiso .aport = NULL, 1506162674Spiso .sport = NULL, 1507162674Spiso .dport = NULL, 1508162674Spiso .maxpktsize = 0 1509162674Spiso }; 1510162674Spiso /* Walk out chain. */ 1511162674Spiso error = find_handler(OUT, IP, la, pip, &ad); 1512162674Spiso if (error == 0) 1513162674Spiso iresult = PKT_ALIAS_OK; 1514162674Spiso else 1515177098Spiso iresult = ProtoAliasOut(la, &pip->ip_src, 1516177098Spiso pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1517162674Spiso } 1518162674Spiso break; 1519127094Sdes default: 1520177098Spiso iresult = ProtoAliasOut(la, &pip->ip_src, 1521177098Spiso pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1522127094Sdes break; 1523127094Sdes } 1524127094Sdes } else { 1525177098Spiso iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum); 1526127094Sdes } 152726026Sbrian 1528127094Sdes SetDefaultAliasAddress(la, addr_save); 1529165243Spisogetout: 1530127094Sdes return (iresult); 153126026Sbrian} 153263899Sarchie 153363899Sarchieint 1534127094SdesLibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */ 1535127094Sdes int maxpacketsize /* for error checking */ 1536127094Sdes) 153763899Sarchie{ 1538127094Sdes struct ip *pip; 1539127094Sdes struct icmp *ic; 1540127094Sdes struct udphdr *ud; 1541127094Sdes struct tcphdr *tc; 1542131614Sdes struct alias_link *lnk; 1543127094Sdes int iresult = PKT_ALIAS_IGNORED; 154463899Sarchie 1545165243Spiso LIBALIAS_LOCK(la); 1546127094Sdes pip = (struct ip *)ptr; 154763899Sarchie 1548127094Sdes /* Defense against mangled packets */ 1549127094Sdes if (ntohs(pip->ip_len) > maxpacketsize 1550127094Sdes || (pip->ip_hl << 2) > maxpacketsize) 1551165243Spiso goto getout; 155263899Sarchie 1553131699Sdes ud = (struct udphdr *)ip_next(pip); 1554131699Sdes tc = (struct tcphdr *)ip_next(pip); 1555131699Sdes ic = (struct icmp *)ip_next(pip); 155663899Sarchie 1557127094Sdes /* Find a link */ 1558127094Sdes if (pip->ip_p == IPPROTO_UDP) 1559131614Sdes lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1560127094Sdes ud->uh_dport, ud->uh_sport, 1561127094Sdes IPPROTO_UDP, 0); 1562127094Sdes else if (pip->ip_p == IPPROTO_TCP) 1563131614Sdes lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1564127094Sdes tc->th_dport, tc->th_sport, 1565127094Sdes IPPROTO_TCP, 0); 1566127094Sdes else if (pip->ip_p == IPPROTO_ICMP) 1567131614Sdes lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0); 1568127094Sdes else 1569131614Sdes lnk = NULL; 157063899Sarchie 1571127094Sdes /* Change it from an aliased packet to an unaliased packet */ 1572131614Sdes if (lnk != NULL) { 1573127094Sdes if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) { 1574127094Sdes int accumulate; 1575127094Sdes struct in_addr original_address; 1576127094Sdes u_short original_port; 157763899Sarchie 1578131614Sdes original_address = GetOriginalAddress(lnk); 1579131614Sdes original_port = GetOriginalPort(lnk); 158099207Sbrian 1581127094Sdes /* Adjust TCP/UDP checksum */ 1582127689Sdes accumulate = twowords(&pip->ip_src); 1583127689Sdes accumulate -= twowords(&original_address); 158463899Sarchie 1585127094Sdes if (pip->ip_p == IPPROTO_UDP) { 1586127094Sdes accumulate += ud->uh_sport; 1587127094Sdes accumulate -= original_port; 1588127094Sdes ADJUST_CHECKSUM(accumulate, ud->uh_sum); 1589127094Sdes } else { 1590127094Sdes accumulate += tc->th_sport; 1591127094Sdes accumulate -= original_port; 1592127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 1593127094Sdes } 159463899Sarchie 1595127094Sdes /* Adjust IP checksum */ 1596127094Sdes DifferentialChecksum(&pip->ip_sum, 1597127689Sdes &original_address, &pip->ip_src, 2); 159863899Sarchie 1599127094Sdes /* Un-alias source address and port number */ 1600127094Sdes pip->ip_src = original_address; 1601127094Sdes if (pip->ip_p == IPPROTO_UDP) 1602127094Sdes ud->uh_sport = original_port; 1603127094Sdes else 1604127094Sdes tc->th_sport = original_port; 160599207Sbrian 1606127094Sdes iresult = PKT_ALIAS_OK; 160763899Sarchie 1608127094Sdes } else if (pip->ip_p == IPPROTO_ICMP) { 160963899Sarchie 1610127094Sdes int accumulate; 1611127094Sdes struct in_addr original_address; 1612127094Sdes u_short original_id; 161363899Sarchie 1614131614Sdes original_address = GetOriginalAddress(lnk); 1615131614Sdes original_id = GetOriginalPort(lnk); 161663899Sarchie 1617127094Sdes /* Adjust ICMP checksum */ 1618127689Sdes accumulate = twowords(&pip->ip_src); 1619127689Sdes accumulate -= twowords(&original_address); 1620127094Sdes accumulate += ic->icmp_id; 1621127094Sdes accumulate -= original_id; 1622127094Sdes ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 162363899Sarchie 1624127094Sdes /* Adjust IP checksum */ 1625127094Sdes DifferentialChecksum(&pip->ip_sum, 1626127689Sdes &original_address, &pip->ip_src, 2); 162763899Sarchie 1628127094Sdes /* Un-alias source address and port number */ 1629127094Sdes pip->ip_src = original_address; 1630127094Sdes ic->icmp_id = original_id; 163163899Sarchie 1632127094Sdes iresult = PKT_ALIAS_OK; 1633127094Sdes } 1634127094Sdes } 1635165243Spisogetout: 1636165243Spiso LIBALIAS_UNLOCK(la); 1637127094Sdes return (iresult); 163863899Sarchie 163963899Sarchie} 1640162674Spiso 1641162674Spiso#ifndef _KERNEL 1642162674Spiso 1643162674Spisoint 1644162674SpisoLibAliasRefreshModules(void) 1645162674Spiso{ 1646162674Spiso char buf[256], conf[] = "/etc/libalias.conf"; 1647162674Spiso FILE *fd; 1648164798Spiso int i, len; 1649162674Spiso 1650162674Spiso fd = fopen(conf, "r"); 1651162674Spiso if (fd == NULL) 1652162674Spiso err(1, "fopen(%s)", conf); 1653162674Spiso 1654162674Spiso LibAliasUnLoadAllModule(); 1655162674Spiso 1656162674Spiso for (;;) { 1657162674Spiso fgets(buf, 256, fd); 1658178730Smarck if (feof(fd)) 1659162674Spiso break; 1660162674Spiso len = strlen(buf); 1661162674Spiso if (len > 1) { 1662164798Spiso for (i = 0; i < len; i++) 1663164798Spiso if (!isspace(buf[i])) 1664164798Spiso break; 1665164798Spiso if (buf[i] == '#') 1666164798Spiso continue; 1667162674Spiso buf[len - 1] = '\0'; 1668162674Spiso LibAliasLoadModule(buf); 1669162674Spiso } 1670162674Spiso } 1671198539Sbrueffer fclose(fd); 1672162674Spiso return (0); 1673162674Spiso} 1674162674Spiso 1675162674Spisoint 1676162674SpisoLibAliasLoadModule(char *path) 1677162674Spiso{ 1678162674Spiso struct dll *t; 1679162674Spiso void *handle; 1680162674Spiso struct proto_handler *m; 1681162674Spiso const char *error; 1682162674Spiso moduledata_t *p; 1683162674Spiso 1684162674Spiso handle = dlopen (path, RTLD_LAZY); 1685162674Spiso if (!handle) { 1686164798Spiso fprintf(stderr, "%s\n", dlerror()); 1687164798Spiso return (EINVAL); 1688162674Spiso } 1689162674Spiso 1690162674Spiso p = dlsym(handle, "alias_mod"); 1691162674Spiso if ((error = dlerror()) != NULL) { 1692164798Spiso fprintf(stderr, "%s\n", dlerror()); 1693164798Spiso return (EINVAL); 1694162674Spiso } 1695164798Spiso 1696162674Spiso t = malloc(sizeof(struct dll)); 1697162674Spiso if (t == NULL) 1698162674Spiso return (ENOMEM); 1699162674Spiso strncpy(t->name, p->name, DLL_LEN); 1700162674Spiso t->handle = handle; 1701162674Spiso if (attach_dll(t) == EEXIST) { 1702162674Spiso free(t); 1703164798Spiso fprintf(stderr, "dll conflict\n"); 1704162674Spiso return (EEXIST); 1705162674Spiso } 1706162674Spiso 1707162674Spiso m = dlsym(t->handle, "handlers"); 1708162674Spiso if ((error = dlerror()) != NULL) { 1709164798Spiso fprintf(stderr, "%s\n", error); 1710164798Spiso return (EINVAL); 1711164798Spiso } 1712162674Spiso 1713162674Spiso LibAliasAttachHandlers(m); 1714162674Spiso return (0); 1715162674Spiso} 1716162674Spiso 1717162674Spisoint 1718162674SpisoLibAliasUnLoadAllModule(void) 1719162674Spiso{ 1720162674Spiso struct dll *t; 1721162674Spiso struct proto_handler *p; 1722162674Spiso 1723162674Spiso /* Unload all modules then reload everything. */ 1724162674Spiso while ((p = first_handler()) != NULL) { 1725162674Spiso detach_handler(p); 1726162674Spiso } 1727162674Spiso while ((t = walk_dll_chain()) != NULL) { 1728162674Spiso dlclose(t->handle); 1729162674Spiso free(t); 1730162674Spiso } 1731162674Spiso return (1); 1732162674Spiso} 1733162674Spiso 1734162674Spiso#endif 1735164797Spiso 1736164797Spiso#ifdef _KERNEL 1737164797Spiso/* 1738165243Spiso * m_megapullup() - this function is a big hack. 1739165243Spiso * Thankfully, it's only used in ng_nat and ipfw+nat. 1740164797Spiso * 1741179478Smav * It allocates an mbuf with cluster and copies the specified part of the chain 1742179478Smav * into cluster, so that it is all contiguous and can be accessed via a plain 1743179478Smav * (char *) pointer. This is required, because libalias doesn't know how to 1744179478Smav * handle mbuf chains. 1745165243Spiso * 1746179478Smav * On success, m_megapullup returns an mbuf (possibly with cluster) containing 1747179478Smav * the input packet, on failure NULL. The input packet is always consumed. 1748164797Spiso */ 1749164797Spisostruct mbuf * 1750164797Spisom_megapullup(struct mbuf *m, int len) { 1751164797Spiso struct mbuf *mcl; 1752248416Sglebius 1753179478Smav if (len > m->m_pkthdr.len) 1754164797Spiso goto bad; 1755248416Sglebius 1756248416Sglebius if (m->m_next == NULL && M_WRITABLE(m)) 1757179478Smav return (m); 1758179478Smav 1759248416Sglebius mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR); 1760179478Smav if (mcl == NULL) 1761179478Smav goto bad; 1762248416Sglebius m_align(mcl, len); 1763164797Spiso m_move_pkthdr(mcl, m); 1764179478Smav m_copydata(m, 0, len, mtod(mcl, caddr_t)); 1765179478Smav mcl->m_len = mcl->m_pkthdr.len = len; 1766164797Spiso m_freem(m); 1767248416Sglebius 1768164797Spiso return (mcl); 1769164797Spisobad: 1770164797Spiso m_freem(m); 1771164797Spiso return (NULL); 1772164797Spiso} 1773164797Spiso#endif 1774