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: stable/10/sys/netinet/libalias/alias.c 335474 2018-06-21 11:24:20Z ae $"); 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 70359356Sru/* Return if proxy-only mode is enabled */ 704127094Sdes if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 705131613Sdes return (PKT_ALIAS_OK); 70644307Sbrian 707318519Seugen if (!create) 708318519Seugen return (PKT_ALIAS_IGNORED); 709318519Seugen 710177098Spiso lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p); 711131614Sdes if (lnk != NULL) { 712127094Sdes struct in_addr alias_address; 71359356Sru 714131614Sdes alias_address = GetAliasAddress(lnk); 71559356Sru 71659356Sru/* Change source address */ 717177098Spiso DifferentialChecksum(ip_sum, 718177098Spiso &alias_address, ip_src, 2); 719177098Spiso *ip_src = alias_address; 72059356Sru 721127094Sdes return (PKT_ALIAS_OK); 722127094Sdes } 723127094Sdes return (PKT_ALIAS_IGNORED); 72444307Sbrian} 72544307Sbrian 72644307Sbrian 72761861Srustatic int 728124621SphkUdpAliasIn(struct libalias *la, struct ip *pip) 72926026Sbrian{ 730127094Sdes struct udphdr *ud; 731131614Sdes struct alias_link *lnk; 73226026Sbrian 733165243Spiso LIBALIAS_LOCK_ASSERT(la); 73444307Sbrian 735131699Sdes ud = (struct udphdr *)ip_next(pip); 73626026Sbrian 737131614Sdes lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 738127094Sdes ud->uh_sport, ud->uh_dport, 739179920Smav IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 740131614Sdes if (lnk != NULL) { 741127094Sdes struct in_addr alias_address; 742127094Sdes struct in_addr original_address; 743179920Smav struct in_addr proxy_address; 744127094Sdes u_short alias_port; 745179920Smav u_short proxy_port; 746127094Sdes int accumulate; 747190938Spiso int error; 748162674Spiso struct alias_data ad = { 749162674Spiso .lnk = lnk, 750162674Spiso .oaddr = &original_address, 751162674Spiso .aaddr = &alias_address, 752162674Spiso .aport = &alias_port, 753162674Spiso .sport = &ud->uh_sport, 754162674Spiso .dport = &ud->uh_dport, 755162674Spiso .maxpktsize = 0 756162674Spiso }; 75726026Sbrian 758131614Sdes alias_address = GetAliasAddress(lnk); 759131614Sdes original_address = GetOriginalAddress(lnk); 760179920Smav proxy_address = GetProxyAddress(lnk); 761127094Sdes alias_port = ud->uh_dport; 762131614Sdes ud->uh_dport = GetOriginalPort(lnk); 763179920Smav proxy_port = GetProxyPort(lnk); 76426026Sbrian 765162674Spiso /* Walk out chain. */ 766162674Spiso error = find_handler(IN, UDP, la, pip, &ad); 767190941Spiso /* If we cannot figure out the packet, ignore it. */ 768190941Spiso if (error < 0) 769190941Spiso return (PKT_ALIAS_IGNORED); 77036321Samurai 77126026Sbrian/* If UDP checksum is not zero, then adjust since destination port */ 77266545Sru/* is being unaliased and destination address is being altered. */ 773127094Sdes if (ud->uh_sum != 0) { 774127094Sdes accumulate = alias_port; 775127094Sdes accumulate -= ud->uh_dport; 776127689Sdes accumulate += twowords(&alias_address); 777127689Sdes accumulate -= twowords(&original_address); 778179920Smav 779179920Smav/* If this is a proxy packet, modify checksum because of source change.*/ 780179920Smav if (proxy_port != 0) { 781179920Smav accumulate += ud->uh_sport; 782179920Smav accumulate -= proxy_port; 783179920Smav } 784179920Smav 785179920Smav if (proxy_address.s_addr != 0) { 786179920Smav accumulate += twowords(&pip->ip_src); 787179920Smav accumulate -= twowords(&proxy_address); 788179920Smav } 789179920Smav 790127094Sdes ADJUST_CHECKSUM(accumulate, ud->uh_sum); 791127094Sdes } 792179920Smav/* XXX: Could the two if's below be concatenated to one ? */ 793179920Smav/* Restore source port and/or address in case of proxying*/ 794179920Smav 795179920Smav if (proxy_port != 0) 796179920Smav ud->uh_sport = proxy_port; 797179920Smav 798179920Smav if (proxy_address.s_addr != 0) { 799179920Smav DifferentialChecksum(&pip->ip_sum, 800179920Smav &proxy_address, &pip->ip_src, 2); 801179920Smav pip->ip_src = proxy_address; 802179920Smav } 803179920Smav 80426026Sbrian/* Restore original IP address */ 805127094Sdes DifferentialChecksum(&pip->ip_sum, 806127689Sdes &original_address, &pip->ip_dst, 2); 807127094Sdes pip->ip_dst = original_address; 80841759Sdillon 809190941Spiso return (PKT_ALIAS_OK); 810127094Sdes } 811127094Sdes return (PKT_ALIAS_IGNORED); 81226026Sbrian} 81326026Sbrian 81426026Sbrianstatic int 815179920SmavUdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 81626026Sbrian{ 817127094Sdes struct udphdr *ud; 818131614Sdes struct alias_link *lnk; 819179920Smav struct in_addr dest_address; 820179920Smav struct in_addr proxy_server_address; 821179920Smav u_short dest_port; 822179920Smav u_short proxy_server_port; 823179920Smav int proxy_type; 824162674Spiso int error; 82526026Sbrian 826165243Spiso LIBALIAS_LOCK_ASSERT(la); 82744307Sbrian 828179920Smav/* Return if proxy-only mode is enabled and not proxyrule found.*/ 829131699Sdes ud = (struct udphdr *)ip_next(pip); 830179920Smav proxy_type = ProxyCheck(la, &proxy_server_address, 831179920Smav &proxy_server_port, pip->ip_src, pip->ip_dst, 832179920Smav ud->uh_dport, pip->ip_p); 833179920Smav if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 834179920Smav return (PKT_ALIAS_OK); 83526026Sbrian 836179920Smav/* If this is a transparent proxy, save original destination, 837179920Smav * then alter the destination and adjust checksums */ 838179920Smav dest_port = ud->uh_dport; 839179920Smav dest_address = pip->ip_dst; 840179920Smav 841179920Smav if (proxy_type != 0) { 842179920Smav int accumulate; 843179920Smav 844179920Smav accumulate = twowords(&pip->ip_dst); 845179920Smav accumulate -= twowords(&proxy_server_address); 846179920Smav 847179920Smav ADJUST_CHECKSUM(accumulate, pip->ip_sum); 848179920Smav 849179920Smav if (ud->uh_sum != 0) { 850179920Smav accumulate = twowords(&pip->ip_dst); 851179920Smav accumulate -= twowords(&proxy_server_address); 852179920Smav accumulate += ud->uh_dport; 853179920Smav accumulate -= proxy_server_port; 854179920Smav ADJUST_CHECKSUM(accumulate, ud->uh_sum); 855179920Smav } 856179920Smav pip->ip_dst = proxy_server_address; 857179920Smav ud->uh_dport = proxy_server_port; 858179920Smav } 859131614Sdes lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 860127094Sdes ud->uh_sport, ud->uh_dport, 861131566Sphk IPPROTO_UDP, create); 862131614Sdes if (lnk != NULL) { 863127094Sdes u_short alias_port; 864127094Sdes struct in_addr alias_address; 865162674Spiso struct alias_data ad = { 866162674Spiso .lnk = lnk, 867162674Spiso .oaddr = NULL, 868162674Spiso .aaddr = &alias_address, 869162674Spiso .aport = &alias_port, 870162674Spiso .sport = &ud->uh_sport, 871162674Spiso .dport = &ud->uh_dport, 872162674Spiso .maxpktsize = 0 873162674Spiso }; 87426026Sbrian 875179920Smav/* Save original destination address, if this is a proxy packet. 876179920Smav * Also modify packet to include destination encoding. This may 877179920Smav * change the size of IP header. */ 878179920Smav if (proxy_type != 0) { 879179920Smav SetProxyPort(lnk, dest_port); 880179920Smav SetProxyAddress(lnk, dest_address); 881179920Smav ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 882179920Smav ud = (struct udphdr *)ip_next(pip); 883179920Smav } 884179920Smav 885131614Sdes alias_address = GetAliasAddress(lnk); 886131614Sdes alias_port = GetAliasPort(lnk); 88726026Sbrian 888162674Spiso /* Walk out chain. */ 889162674Spiso error = find_handler(OUT, UDP, la, pip, &ad); 89036321Samurai 89126026Sbrian/* If UDP checksum is not zero, adjust since source port is */ 89226026Sbrian/* being aliased and source address is being altered */ 893127094Sdes if (ud->uh_sum != 0) { 894127094Sdes int accumulate; 89526026Sbrian 896127094Sdes accumulate = ud->uh_sport; 897127094Sdes accumulate -= alias_port; 898127689Sdes accumulate += twowords(&pip->ip_src); 899127689Sdes accumulate -= twowords(&alias_address); 900127094Sdes ADJUST_CHECKSUM(accumulate, ud->uh_sum); 901127094Sdes } 90236321Samurai/* Put alias port in UDP header */ 903127094Sdes ud->uh_sport = alias_port; 90426026Sbrian 90526026Sbrian/* Change source address */ 906127094Sdes DifferentialChecksum(&pip->ip_sum, 907127689Sdes &alias_address, &pip->ip_src, 2); 908127094Sdes pip->ip_src = alias_address; 90926026Sbrian 910127094Sdes return (PKT_ALIAS_OK); 911127094Sdes } 912127094Sdes return (PKT_ALIAS_IGNORED); 91326026Sbrian} 91426026Sbrian 91526026Sbrian 91626026Sbrian 91726026Sbrianstatic int 918124621SphkTcpAliasIn(struct libalias *la, struct ip *pip) 91926026Sbrian{ 920127094Sdes struct tcphdr *tc; 921131614Sdes struct alias_link *lnk; 92226026Sbrian 923165243Spiso LIBALIAS_LOCK_ASSERT(la); 924131699Sdes tc = (struct tcphdr *)ip_next(pip); 92526026Sbrian 926131614Sdes lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 927127094Sdes tc->th_sport, tc->th_dport, 928127094Sdes IPPROTO_TCP, 929127094Sdes !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 930131614Sdes if (lnk != NULL) { 931127094Sdes struct in_addr alias_address; 932127094Sdes struct in_addr original_address; 933127094Sdes struct in_addr proxy_address; 934127094Sdes u_short alias_port; 935127094Sdes u_short proxy_port; 936162674Spiso int accumulate, error; 93726026Sbrian 938162674Spiso /* 939162674Spiso * The init of MANY vars is a bit below, but aliashandlepptpin 940162674Spiso * seems to need the destination port that came within the 941162674Spiso * packet and not the original one looks below [*]. 942162674Spiso */ 94361861Sru 944162674Spiso struct alias_data ad = { 945162674Spiso .lnk = lnk, 946162674Spiso .oaddr = NULL, 947162674Spiso .aaddr = NULL, 948162674Spiso .aport = NULL, 949162674Spiso .sport = &tc->th_sport, 950162674Spiso .dport = &tc->th_dport, 951162674Spiso .maxpktsize = 0 952162674Spiso }; 953162674Spiso 954162674Spiso /* Walk out chain. */ 955162674Spiso error = find_handler(IN, TCP, la, pip, &ad); 956162674Spiso 957131614Sdes alias_address = GetAliasAddress(lnk); 958131614Sdes original_address = GetOriginalAddress(lnk); 959131614Sdes proxy_address = GetProxyAddress(lnk); 960127094Sdes alias_port = tc->th_dport; 961131614Sdes tc->th_dport = GetOriginalPort(lnk); 962131614Sdes proxy_port = GetProxyPort(lnk); 96326026Sbrian 964162674Spiso /* 965162674Spiso * Look above, if anyone is going to add find_handler AFTER 966162674Spiso * this aliashandlepptpin/point, please redo alias_data too. 967162674Spiso * Uncommenting the piece here below should be enough. 968162674Spiso */ 969162674Spiso#if 0 970162674Spiso struct alias_data ad = { 971162674Spiso .lnk = lnk, 972162674Spiso .oaddr = &original_address, 973162674Spiso .aaddr = &alias_address, 974162674Spiso .aport = &alias_port, 975162674Spiso .sport = &ud->uh_sport, 976162674Spiso .dport = &ud->uh_dport, 977162674Spiso .maxpktsize = 0 978162674Spiso }; 979162674Spiso 980162674Spiso /* Walk out chain. */ 981162674Spiso error = find_handler(la, pip, &ad); 982162674Spiso if (error == EHDNOF) 983162674Spiso printf("Protocol handler not found\n"); 984162674Spiso#endif 985162674Spiso 98626026Sbrian/* Adjust TCP checksum since destination port is being unaliased */ 98726026Sbrian/* and destination port is being altered. */ 988127094Sdes accumulate = alias_port; 989127094Sdes accumulate -= tc->th_dport; 990127689Sdes accumulate += twowords(&alias_address); 991127689Sdes accumulate -= twowords(&original_address); 99226026Sbrian 99359356Sru/* If this is a proxy, then modify the TCP source port and 99444307Sbrian checksum accumulation */ 995127094Sdes if (proxy_port != 0) { 996127094Sdes accumulate += tc->th_sport; 997127094Sdes tc->th_sport = proxy_port; 998127094Sdes accumulate -= tc->th_sport; 999127689Sdes accumulate += twowords(&pip->ip_src); 1000127689Sdes accumulate -= twowords(&proxy_address); 1001127094Sdes } 100259356Sru/* See if ACK number needs to be modified */ 1003131614Sdes if (GetAckModified(lnk) == 1) { 1004127094Sdes int delta; 100526026Sbrian 1006176884Spiso tc = (struct tcphdr *)ip_next(pip); 1007176884Spiso delta = GetDeltaAckIn(tc->th_ack, lnk); 1008127094Sdes if (delta != 0) { 1009127689Sdes accumulate += twowords(&tc->th_ack); 1010127094Sdes tc->th_ack = htonl(ntohl(tc->th_ack) - delta); 1011127689Sdes accumulate -= twowords(&tc->th_ack); 1012127094Sdes } 1013127094Sdes } 1014127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 101526026Sbrian 101626026Sbrian/* Restore original IP address */ 1017127689Sdes accumulate = twowords(&pip->ip_dst); 1018127757Sdeischen pip->ip_dst = original_address; 1019127689Sdes accumulate -= twowords(&pip->ip_dst); 102026026Sbrian 102144307Sbrian/* If this is a transparent proxy packet, then modify the source 102244307Sbrian address */ 1023127094Sdes if (proxy_address.s_addr != 0) { 1024127689Sdes accumulate += twowords(&pip->ip_src); 1025127094Sdes pip->ip_src = proxy_address; 1026127689Sdes accumulate -= twowords(&pip->ip_src); 1027127094Sdes } 1028127094Sdes ADJUST_CHECKSUM(accumulate, pip->ip_sum); 102944307Sbrian 103026026Sbrian/* Monitor TCP connection state */ 1031176884Spiso tc = (struct tcphdr *)ip_next(pip); 1032176884Spiso TcpMonitorIn(tc->th_flags, lnk); 103326026Sbrian 1034127094Sdes return (PKT_ALIAS_OK); 1035127094Sdes } 1036127094Sdes return (PKT_ALIAS_IGNORED); 103726026Sbrian} 103826026Sbrian 103926026Sbrianstatic int 1040131566SphkTcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 104126026Sbrian{ 1042162674Spiso int proxy_type, error; 1043127094Sdes u_short dest_port; 1044127094Sdes u_short proxy_server_port; 1045127094Sdes struct in_addr dest_address; 1046127094Sdes struct in_addr proxy_server_address; 1047127094Sdes struct tcphdr *tc; 1048131614Sdes struct alias_link *lnk; 104926026Sbrian 1050165243Spiso LIBALIAS_LOCK_ASSERT(la); 1051131699Sdes tc = (struct tcphdr *)ip_next(pip); 105226026Sbrian 1053147636Sphk if (create) 1054176884Spiso proxy_type = ProxyCheck(la, &proxy_server_address, 1055176884Spiso &proxy_server_port, pip->ip_src, pip->ip_dst, 1056176884Spiso tc->th_dport, pip->ip_p); 1057147636Sphk else 1058147636Sphk proxy_type = 0; 105944307Sbrian 1060127094Sdes if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 1061131613Sdes return (PKT_ALIAS_OK); 106244307Sbrian 106344307Sbrian/* If this is a transparent proxy, save original destination, 106459356Sru then alter the destination and adjust checksums */ 1065127094Sdes dest_port = tc->th_dport; 1066127094Sdes dest_address = pip->ip_dst; 1067127094Sdes if (proxy_type != 0) { 1068127094Sdes int accumulate; 106944307Sbrian 1070127094Sdes accumulate = tc->th_dport; 1071127094Sdes tc->th_dport = proxy_server_port; 1072127094Sdes accumulate -= tc->th_dport; 1073127689Sdes accumulate += twowords(&pip->ip_dst); 1074127689Sdes accumulate -= twowords(&proxy_server_address); 1075127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 107644307Sbrian 1077127689Sdes accumulate = twowords(&pip->ip_dst); 1078127094Sdes pip->ip_dst = proxy_server_address; 1079127689Sdes accumulate -= twowords(&pip->ip_dst); 1080127094Sdes ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1081127094Sdes } 1082131614Sdes lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 1083127094Sdes tc->th_sport, tc->th_dport, 1084131566Sphk IPPROTO_TCP, create); 1085131614Sdes if (lnk == NULL) 1086131566Sphk return (PKT_ALIAS_IGNORED); 1087131614Sdes if (lnk != NULL) { 1088127094Sdes u_short alias_port; 1089127094Sdes struct in_addr alias_address; 1090127094Sdes int accumulate; 1091162674Spiso struct alias_data ad = { 1092162674Spiso .lnk = lnk, 1093162674Spiso .oaddr = NULL, 1094162674Spiso .aaddr = &alias_address, 1095162674Spiso .aport = &alias_port, 1096162674Spiso .sport = &tc->th_sport, 1097162674Spiso .dport = &tc->th_dport, 1098162674Spiso .maxpktsize = maxpacketsize 1099162674Spiso }; 110044307Sbrian 110144307Sbrian/* Save original destination address, if this is a proxy packet. 110288132Sru Also modify packet to include destination encoding. This may 110388132Sru change the size of IP header. */ 1104127094Sdes if (proxy_type != 0) { 1105131614Sdes SetProxyPort(lnk, dest_port); 1106131614Sdes SetProxyAddress(lnk, dest_address); 1107131614Sdes ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 1108131699Sdes tc = (struct tcphdr *)ip_next(pip); 1109127094Sdes } 111044307Sbrian/* Get alias address and port */ 1111131614Sdes alias_port = GetAliasPort(lnk); 1112131614Sdes alias_address = GetAliasAddress(lnk); 111326026Sbrian 111459356Sru/* Monitor TCP connection state */ 1115176884Spiso tc = (struct tcphdr *)ip_next(pip); 1116176884Spiso TcpMonitorOut(tc->th_flags, lnk); 1117162674Spiso 1118162674Spiso /* Walk out chain. */ 1119162674Spiso error = find_handler(OUT, TCP, la, pip, &ad); 112026026Sbrian 112126026Sbrian/* Adjust TCP checksum since source port is being aliased */ 112226026Sbrian/* and source address is being altered */ 1123127094Sdes accumulate = tc->th_sport; 1124127094Sdes tc->th_sport = alias_port; 1125127094Sdes accumulate -= tc->th_sport; 1126127689Sdes accumulate += twowords(&pip->ip_src); 1127127689Sdes accumulate -= twowords(&alias_address); 112844307Sbrian 112926026Sbrian/* Modify sequence number if necessary */ 1130131614Sdes if (GetAckModified(lnk) == 1) { 1131127094Sdes int delta; 1132176884Spiso 1133176884Spiso tc = (struct tcphdr *)ip_next(pip); 1134176884Spiso delta = GetDeltaSeqOut(tc->th_seq, lnk); 1135127094Sdes if (delta != 0) { 1136127689Sdes accumulate += twowords(&tc->th_seq); 1137127094Sdes tc->th_seq = htonl(ntohl(tc->th_seq) + delta); 1138127689Sdes accumulate -= twowords(&tc->th_seq); 1139127094Sdes } 1140127094Sdes } 1141127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 114226026Sbrian 114326026Sbrian/* Change source address */ 1144127689Sdes accumulate = twowords(&pip->ip_src); 1145127094Sdes pip->ip_src = alias_address; 1146127689Sdes accumulate -= twowords(&pip->ip_src); 1147127094Sdes ADJUST_CHECKSUM(accumulate, pip->ip_sum); 114844307Sbrian 1149127094Sdes return (PKT_ALIAS_OK); 1150127094Sdes } 1151127094Sdes return (PKT_ALIAS_IGNORED); 115226026Sbrian} 115326026Sbrian 115426026Sbrian 115526026Sbrian 115626026Sbrian 115726026Sbrian/* Fragment Handling 115826026Sbrian 115926026Sbrian FragmentIn() 116026026Sbrian FragmentOut() 116126026Sbrian 116226026SbrianThe packet aliasing module has a limited ability for handling IP 116326026Sbrianfragments. If the ICMP, TCP or UDP header is in the first fragment 116459356Srureceived, then the ID number of the IP packet is saved, and other 116526026Sbrianfragments are identified according to their ID number and IP address 116626026Sbrianthey were sent from. Pointers to unresolved fragments can also be 116726026Sbriansaved and recalled when a header fragment is seen. 116826026Sbrian*/ 116926026Sbrian 117026026Sbrian/* Local prototypes */ 1171177098Spisostatic int FragmentIn(struct libalias *la, struct in_addr ip_src, 1172179472Smav struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum); 1173177098Spisostatic int FragmentOut(struct libalias *, struct in_addr *ip_src, 1174177098Spiso u_short *ip_sum); 117526026Sbrian 117626026Sbrianstatic int 1177177098SpisoFragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst, 1178179472Smav u_short ip_id, u_short *ip_sum) 117926026Sbrian{ 1180131614Sdes struct alias_link *lnk; 118126026Sbrian 1182165243Spiso LIBALIAS_LOCK_ASSERT(la); 1183177098Spiso lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id); 1184131614Sdes if (lnk != NULL) { 1185127094Sdes struct in_addr original_address; 118626026Sbrian 1187131614Sdes GetFragmentAddr(lnk, &original_address); 1188177098Spiso DifferentialChecksum(ip_sum, 1189177098Spiso &original_address, ip_dst, 2); 1190177098Spiso *ip_dst = original_address; 119199207Sbrian 1192127094Sdes return (PKT_ALIAS_OK); 1193127094Sdes } 1194127094Sdes return (PKT_ALIAS_UNRESOLVED_FRAGMENT); 119526026Sbrian} 119626026Sbrian 119726026Sbrianstatic int 1198177098SpisoFragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum) 119926026Sbrian{ 1200127094Sdes struct in_addr alias_address; 120126026Sbrian 1202165243Spiso LIBALIAS_LOCK_ASSERT(la); 1203177098Spiso alias_address = FindAliasAddress(la, *ip_src); 1204177098Spiso DifferentialChecksum(ip_sum, 1205177098Spiso &alias_address, ip_src, 2); 1206177098Spiso *ip_src = alias_address; 120726026Sbrian 1208127094Sdes return (PKT_ALIAS_OK); 120926026Sbrian} 121026026Sbrian 121126026Sbrian 121226026Sbrian 121326026Sbrian 121426026Sbrian 121526026Sbrian 121626026Sbrian/* Outside World Access 121726026Sbrian 1218131612Sdes PacketAliasSaveFragment() 1219131612Sdes PacketAliasGetFragment() 1220131612Sdes PacketAliasFragmentIn() 1221131612Sdes PacketAliasIn() 1222131612Sdes PacketAliasOut() 1223131612Sdes PacketUnaliasOut() 122426026Sbrian 122526026Sbrian(prototypes in alias.h) 122626026Sbrian*/ 122726026Sbrian 122826026Sbrianint 1229124621SphkLibAliasSaveFragment(struct libalias *la, char *ptr) 123026026Sbrian{ 1231127094Sdes int iresult; 1232131614Sdes struct alias_link *lnk; 1233127094Sdes struct ip *pip; 123426026Sbrian 1235165243Spiso LIBALIAS_LOCK(la); 1236127094Sdes pip = (struct ip *)ptr; 1237131614Sdes lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id); 1238127094Sdes iresult = PKT_ALIAS_ERROR; 1239131614Sdes if (lnk != NULL) { 1240131614Sdes SetFragmentPtr(lnk, ptr); 1241127094Sdes iresult = PKT_ALIAS_OK; 1242127094Sdes } 1243165243Spiso LIBALIAS_UNLOCK(la); 1244127094Sdes return (iresult); 124526026Sbrian} 124626026Sbrian 1247127094Sdeschar * 1248124621SphkLibAliasGetFragment(struct libalias *la, char *ptr) 124926026Sbrian{ 1250131614Sdes struct alias_link *lnk; 1251127094Sdes char *fptr; 1252127094Sdes struct ip *pip; 125326026Sbrian 1254165243Spiso LIBALIAS_LOCK(la); 1255127094Sdes pip = (struct ip *)ptr; 1256131614Sdes lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id); 1257131614Sdes if (lnk != NULL) { 1258131614Sdes GetFragmentPtr(lnk, &fptr); 1259131614Sdes SetFragmentPtr(lnk, NULL); 1260131614Sdes SetExpire(lnk, 0); /* Deletes link */ 1261165243Spiso } else 1262165243Spiso fptr = NULL; 126326026Sbrian 1264165243Spiso LIBALIAS_UNLOCK(la); 1265165243Spiso return (fptr); 126626026Sbrian} 126726026Sbrian 126826026Sbrianvoid 1269127094SdesLibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly 1270127094Sdes * de-aliased header 1271127094Sdes * fragment */ 1272127094Sdes char *ptr_fragment /* Points to fragment which must be 1273127094Sdes * de-aliased */ 1274127094Sdes) 127526026Sbrian{ 1276127094Sdes struct ip *pip; 1277127094Sdes struct ip *fpip; 127826026Sbrian 1279165243Spiso LIBALIAS_LOCK(la); 1280131614Sdes (void)la; 1281127094Sdes pip = (struct ip *)ptr; 1282127094Sdes fpip = (struct ip *)ptr_fragment; 128326026Sbrian 1284127094Sdes DifferentialChecksum(&fpip->ip_sum, 1285127689Sdes &pip->ip_dst, &fpip->ip_dst, 2); 1286127094Sdes fpip->ip_dst = pip->ip_dst; 1287165243Spiso LIBALIAS_UNLOCK(la); 128826026Sbrian} 128926026Sbrian 1290165243Spiso/* Local prototypes */ 1291165243Spisostatic int 1292165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr, 1293165243Spiso int maxpacketsize, int create); 1294165243Spisostatic int 1295165243SpisoLibAliasInLocked(struct libalias *la, char *ptr, 1296165243Spiso int maxpacketsize); 129726026Sbrian 129826026Sbrianint 1299124621SphkLibAliasIn(struct libalias *la, char *ptr, int maxpacketsize) 130026026Sbrian{ 1301165243Spiso int res; 1302165243Spiso 1303165243Spiso LIBALIAS_LOCK(la); 1304165243Spiso res = LibAliasInLocked(la, ptr, maxpacketsize); 1305165243Spiso LIBALIAS_UNLOCK(la); 1306165243Spiso return (res); 1307165243Spiso} 1308165243Spiso 1309165243Spisostatic int 1310165243SpisoLibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) 1311165243Spiso{ 1312127094Sdes struct in_addr alias_addr; 1313127094Sdes struct ip *pip; 1314127094Sdes int iresult; 131526026Sbrian 1316127094Sdes if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1317127094Sdes la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1318165243Spiso iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1319127094Sdes la->packetAliasMode |= PKT_ALIAS_REVERSE; 1320165243Spiso goto getout; 1321127094Sdes } 1322127094Sdes HouseKeeping(la); 1323127094Sdes ClearCheckNewLink(la); 1324127094Sdes pip = (struct ip *)ptr; 1325127094Sdes alias_addr = pip->ip_dst; 132644307Sbrian 1327127094Sdes /* Defense against mangled packets */ 1328127094Sdes if (ntohs(pip->ip_len) > maxpacketsize 1329165243Spiso || (pip->ip_hl << 2) > maxpacketsize) { 1330165243Spiso iresult = PKT_ALIAS_IGNORED; 1331165243Spiso goto getout; 1332165243Spiso } 133399207Sbrian 1334127094Sdes iresult = PKT_ALIAS_IGNORED; 1335127094Sdes if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1336127094Sdes switch (pip->ip_p) { 1337127094Sdes case IPPROTO_ICMP: 1338127094Sdes iresult = IcmpAliasIn(la, pip); 1339127094Sdes break; 1340127094Sdes case IPPROTO_UDP: 1341127094Sdes iresult = UdpAliasIn(la, pip); 1342127094Sdes break; 1343127094Sdes case IPPROTO_TCP: 1344127094Sdes iresult = TcpAliasIn(la, pip); 1345127094Sdes break; 1346188294Spiso#ifdef _KERNEL 1347188294Spiso case IPPROTO_SCTP: 1348188294Spiso iresult = SctpAlias(la, pip, SN_TO_LOCAL); 1349188294Spiso break; 1350188294Spiso#endif 1351162674Spiso case IPPROTO_GRE: { 1352162674Spiso int error; 1353162674Spiso struct alias_data ad = { 1354162674Spiso .lnk = NULL, 1355162674Spiso .oaddr = NULL, 1356162674Spiso .aaddr = NULL, 1357162674Spiso .aport = NULL, 1358162674Spiso .sport = NULL, 1359162674Spiso .dport = NULL, 1360162674Spiso .maxpktsize = 0 1361162674Spiso }; 1362162674Spiso 1363162674Spiso /* Walk out chain. */ 1364162674Spiso error = find_handler(IN, IP, la, pip, &ad); 1365162674Spiso if (error == 0) 1366127094Sdes iresult = PKT_ALIAS_OK; 1367127094Sdes else 1368177098Spiso iresult = ProtoAliasIn(la, pip->ip_src, 1369177098Spiso &pip->ip_dst, pip->ip_p, &pip->ip_sum); 1370162674Spiso } 1371162674Spiso break; 1372127094Sdes default: 1373177098Spiso iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst, 1374177098Spiso pip->ip_p, &pip->ip_sum); 1375127094Sdes break; 1376127094Sdes } 137799207Sbrian 1378127094Sdes if (ntohs(pip->ip_off) & IP_MF) { 1379131614Sdes struct alias_link *lnk; 138026026Sbrian 1381131614Sdes lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id); 1382131614Sdes if (lnk != NULL) { 1383127094Sdes iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; 1384131614Sdes SetFragmentAddr(lnk, pip->ip_dst); 1385127094Sdes } else { 1386127094Sdes iresult = PKT_ALIAS_ERROR; 1387127094Sdes } 1388127094Sdes } 1389127094Sdes } else { 1390177098Spiso iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id, 1391177098Spiso &pip->ip_sum); 1392127094Sdes } 139326026Sbrian 1394165243Spisogetout: 1395127094Sdes return (iresult); 139626026Sbrian} 139726026Sbrian 139826026Sbrian 139926026Sbrian 140026026Sbrian/* Unregistered address ranges */ 140126026Sbrian 140226026Sbrian/* 10.0.0.0 -> 10.255.255.255 */ 140326026Sbrian#define UNREG_ADDR_A_LOWER 0x0a000000 140426026Sbrian#define UNREG_ADDR_A_UPPER 0x0affffff 140526026Sbrian 140626026Sbrian/* 172.16.0.0 -> 172.31.255.255 */ 140726026Sbrian#define UNREG_ADDR_B_LOWER 0xac100000 140826026Sbrian#define UNREG_ADDR_B_UPPER 0xac1fffff 140926026Sbrian 141026026Sbrian/* 192.168.0.0 -> 192.168.255.255 */ 141126026Sbrian#define UNREG_ADDR_C_LOWER 0xc0a80000 141226026Sbrian#define UNREG_ADDR_C_UPPER 0xc0a8ffff 141326026Sbrian 141426026Sbrianint 1415165243SpisoLibAliasOut(struct libalias *la, char *ptr, int maxpacketsize) 141626026Sbrian{ 1417165243Spiso int res; 1418165243Spiso 1419165243Spiso LIBALIAS_LOCK(la); 1420165243Spiso res = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1421165243Spiso LIBALIAS_UNLOCK(la); 1422165243Spiso return (res); 1423131566Sphk} 1424131566Sphk 1425131566Sphkint 1426165243SpisoLibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create) 1427165243Spiso{ 1428165243Spiso int res; 1429165243Spiso 1430165243Spiso LIBALIAS_LOCK(la); 1431165243Spiso res = LibAliasOutLocked(la, ptr, maxpacketsize, create); 1432165243Spiso LIBALIAS_UNLOCK(la); 1433165243Spiso return (res); 1434165243Spiso} 1435165243Spiso 1436165243Spisostatic int 1437165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ 1438131566Sphk int maxpacketsize, /* How much the packet data may grow (FTP 1439131566Sphk * and IRC inline changes) */ 1440165243Spiso int create /* Create new entries ? */ 1441131566Sphk) 1442131566Sphk{ 1443127094Sdes int iresult; 1444127094Sdes struct in_addr addr_save; 1445127094Sdes struct ip *pip; 144626026Sbrian 1447127094Sdes if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1448127094Sdes la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1449165243Spiso iresult = LibAliasInLocked(la, ptr, maxpacketsize); 1450127094Sdes la->packetAliasMode |= PKT_ALIAS_REVERSE; 1451165243Spiso goto getout; 1452127094Sdes } 1453127094Sdes HouseKeeping(la); 1454127094Sdes ClearCheckNewLink(la); 1455127094Sdes pip = (struct ip *)ptr; 145644307Sbrian 1457127094Sdes /* Defense against mangled packets */ 1458127094Sdes if (ntohs(pip->ip_len) > maxpacketsize 1459165243Spiso || (pip->ip_hl << 2) > maxpacketsize) { 1460165243Spiso iresult = PKT_ALIAS_IGNORED; 1461165243Spiso goto getout; 1462165243Spiso } 146326026Sbrian 1464127094Sdes addr_save = GetDefaultAliasAddress(la); 1465127094Sdes if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) { 1466127094Sdes u_long addr; 1467127094Sdes int iclass; 146832377Seivind 1469127094Sdes iclass = 0; 1470127094Sdes addr = ntohl(pip->ip_src.s_addr); 1471127094Sdes if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) 1472127094Sdes iclass = 3; 1473127094Sdes else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) 1474127094Sdes iclass = 2; 1475127094Sdes else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) 1476127094Sdes iclass = 1; 147726026Sbrian 1478127094Sdes if (iclass == 0) { 1479127094Sdes SetDefaultAliasAddress(la, pip->ip_src); 1480127094Sdes } 1481127094Sdes } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) { 1482127094Sdes SetDefaultAliasAddress(la, pip->ip_src); 1483127094Sdes } 1484127094Sdes iresult = PKT_ALIAS_IGNORED; 1485127094Sdes if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1486127094Sdes switch (pip->ip_p) { 1487127094Sdes case IPPROTO_ICMP: 1488131566Sphk iresult = IcmpAliasOut(la, pip, create); 1489127094Sdes break; 1490127094Sdes case IPPROTO_UDP: 1491179920Smav iresult = UdpAliasOut(la, pip, maxpacketsize, create); 1492127094Sdes break; 1493188294Spiso case IPPROTO_TCP: 1494131566Sphk iresult = TcpAliasOut(la, pip, maxpacketsize, create); 1495127094Sdes break; 1496188294Spiso#ifdef _KERNEL 1497188294Spiso case IPPROTO_SCTP: 1498188294Spiso iresult = SctpAlias(la, pip, SN_TO_GLOBAL); 1499188294Spiso break; 1500188294Spiso#endif 1501188294Spiso case IPPROTO_GRE: { 1502162674Spiso int error; 1503162674Spiso struct alias_data ad = { 1504162674Spiso .lnk = NULL, 1505162674Spiso .oaddr = NULL, 1506162674Spiso .aaddr = NULL, 1507162674Spiso .aport = NULL, 1508162674Spiso .sport = NULL, 1509162674Spiso .dport = NULL, 1510162674Spiso .maxpktsize = 0 1511162674Spiso }; 1512162674Spiso /* Walk out chain. */ 1513162674Spiso error = find_handler(OUT, IP, la, pip, &ad); 1514162674Spiso if (error == 0) 1515162674Spiso iresult = PKT_ALIAS_OK; 1516162674Spiso else 1517177098Spiso iresult = ProtoAliasOut(la, &pip->ip_src, 1518177098Spiso pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1519162674Spiso } 1520162674Spiso break; 1521127094Sdes default: 1522177098Spiso iresult = ProtoAliasOut(la, &pip->ip_src, 1523177098Spiso pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1524127094Sdes break; 1525127094Sdes } 1526127094Sdes } else { 1527177098Spiso iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum); 1528127094Sdes } 152926026Sbrian 1530127094Sdes SetDefaultAliasAddress(la, addr_save); 1531165243Spisogetout: 1532127094Sdes return (iresult); 153326026Sbrian} 153463899Sarchie 153563899Sarchieint 1536127094SdesLibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */ 1537127094Sdes int maxpacketsize /* for error checking */ 1538127094Sdes) 153963899Sarchie{ 1540127094Sdes struct ip *pip; 1541127094Sdes struct icmp *ic; 1542127094Sdes struct udphdr *ud; 1543127094Sdes struct tcphdr *tc; 1544131614Sdes struct alias_link *lnk; 1545127094Sdes int iresult = PKT_ALIAS_IGNORED; 154663899Sarchie 1547165243Spiso LIBALIAS_LOCK(la); 1548127094Sdes pip = (struct ip *)ptr; 154963899Sarchie 1550127094Sdes /* Defense against mangled packets */ 1551127094Sdes if (ntohs(pip->ip_len) > maxpacketsize 1552127094Sdes || (pip->ip_hl << 2) > maxpacketsize) 1553165243Spiso goto getout; 155463899Sarchie 1555131699Sdes ud = (struct udphdr *)ip_next(pip); 1556131699Sdes tc = (struct tcphdr *)ip_next(pip); 1557131699Sdes ic = (struct icmp *)ip_next(pip); 155863899Sarchie 1559127094Sdes /* Find a link */ 1560127094Sdes if (pip->ip_p == IPPROTO_UDP) 1561131614Sdes lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1562127094Sdes ud->uh_dport, ud->uh_sport, 1563127094Sdes IPPROTO_UDP, 0); 1564127094Sdes else if (pip->ip_p == IPPROTO_TCP) 1565131614Sdes lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1566127094Sdes tc->th_dport, tc->th_sport, 1567127094Sdes IPPROTO_TCP, 0); 1568127094Sdes else if (pip->ip_p == IPPROTO_ICMP) 1569131614Sdes lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0); 1570127094Sdes else 1571131614Sdes lnk = NULL; 157263899Sarchie 1573127094Sdes /* Change it from an aliased packet to an unaliased packet */ 1574131614Sdes if (lnk != NULL) { 1575127094Sdes if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) { 1576127094Sdes int accumulate; 1577127094Sdes struct in_addr original_address; 1578127094Sdes u_short original_port; 157963899Sarchie 1580131614Sdes original_address = GetOriginalAddress(lnk); 1581131614Sdes original_port = GetOriginalPort(lnk); 158299207Sbrian 1583127094Sdes /* Adjust TCP/UDP checksum */ 1584127689Sdes accumulate = twowords(&pip->ip_src); 1585127689Sdes accumulate -= twowords(&original_address); 158663899Sarchie 1587127094Sdes if (pip->ip_p == IPPROTO_UDP) { 1588127094Sdes accumulate += ud->uh_sport; 1589127094Sdes accumulate -= original_port; 1590127094Sdes ADJUST_CHECKSUM(accumulate, ud->uh_sum); 1591127094Sdes } else { 1592127094Sdes accumulate += tc->th_sport; 1593127094Sdes accumulate -= original_port; 1594127094Sdes ADJUST_CHECKSUM(accumulate, tc->th_sum); 1595127094Sdes } 159663899Sarchie 1597127094Sdes /* Adjust IP checksum */ 1598127094Sdes DifferentialChecksum(&pip->ip_sum, 1599127689Sdes &original_address, &pip->ip_src, 2); 160063899Sarchie 1601127094Sdes /* Un-alias source address and port number */ 1602127094Sdes pip->ip_src = original_address; 1603127094Sdes if (pip->ip_p == IPPROTO_UDP) 1604127094Sdes ud->uh_sport = original_port; 1605127094Sdes else 1606127094Sdes tc->th_sport = original_port; 160799207Sbrian 1608127094Sdes iresult = PKT_ALIAS_OK; 160963899Sarchie 1610127094Sdes } else if (pip->ip_p == IPPROTO_ICMP) { 161163899Sarchie 1612127094Sdes int accumulate; 1613127094Sdes struct in_addr original_address; 1614127094Sdes u_short original_id; 161563899Sarchie 1616131614Sdes original_address = GetOriginalAddress(lnk); 1617131614Sdes original_id = GetOriginalPort(lnk); 161863899Sarchie 1619127094Sdes /* Adjust ICMP checksum */ 1620127689Sdes accumulate = twowords(&pip->ip_src); 1621127689Sdes accumulate -= twowords(&original_address); 1622127094Sdes accumulate += ic->icmp_id; 1623127094Sdes accumulate -= original_id; 1624127094Sdes ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 162563899Sarchie 1626127094Sdes /* Adjust IP checksum */ 1627127094Sdes DifferentialChecksum(&pip->ip_sum, 1628127689Sdes &original_address, &pip->ip_src, 2); 162963899Sarchie 1630127094Sdes /* Un-alias source address and port number */ 1631127094Sdes pip->ip_src = original_address; 1632127094Sdes ic->icmp_id = original_id; 163363899Sarchie 1634127094Sdes iresult = PKT_ALIAS_OK; 1635127094Sdes } 1636127094Sdes } 1637165243Spisogetout: 1638165243Spiso LIBALIAS_UNLOCK(la); 1639127094Sdes return (iresult); 164063899Sarchie 164163899Sarchie} 1642162674Spiso 1643162674Spiso#ifndef _KERNEL 1644162674Spiso 1645162674Spisoint 1646162674SpisoLibAliasRefreshModules(void) 1647162674Spiso{ 1648162674Spiso char buf[256], conf[] = "/etc/libalias.conf"; 1649162674Spiso FILE *fd; 1650164798Spiso int i, len; 1651162674Spiso 1652162674Spiso fd = fopen(conf, "r"); 1653162674Spiso if (fd == NULL) 1654162674Spiso err(1, "fopen(%s)", conf); 1655162674Spiso 1656162674Spiso LibAliasUnLoadAllModule(); 1657162674Spiso 1658162674Spiso for (;;) { 1659162674Spiso fgets(buf, 256, fd); 1660178730Smarck if (feof(fd)) 1661162674Spiso break; 1662162674Spiso len = strlen(buf); 1663162674Spiso if (len > 1) { 1664164798Spiso for (i = 0; i < len; i++) 1665164798Spiso if (!isspace(buf[i])) 1666164798Spiso break; 1667164798Spiso if (buf[i] == '#') 1668164798Spiso continue; 1669162674Spiso buf[len - 1] = '\0'; 1670162674Spiso LibAliasLoadModule(buf); 1671162674Spiso } 1672162674Spiso } 1673198539Sbrueffer fclose(fd); 1674162674Spiso return (0); 1675162674Spiso} 1676162674Spiso 1677162674Spisoint 1678162674SpisoLibAliasLoadModule(char *path) 1679162674Spiso{ 1680162674Spiso struct dll *t; 1681162674Spiso void *handle; 1682162674Spiso struct proto_handler *m; 1683162674Spiso const char *error; 1684162674Spiso moduledata_t *p; 1685162674Spiso 1686162674Spiso handle = dlopen (path, RTLD_LAZY); 1687162674Spiso if (!handle) { 1688164798Spiso fprintf(stderr, "%s\n", dlerror()); 1689164798Spiso return (EINVAL); 1690162674Spiso } 1691162674Spiso 1692162674Spiso p = dlsym(handle, "alias_mod"); 1693162674Spiso if ((error = dlerror()) != NULL) { 1694164798Spiso fprintf(stderr, "%s\n", dlerror()); 1695164798Spiso return (EINVAL); 1696162674Spiso } 1697164798Spiso 1698162674Spiso t = malloc(sizeof(struct dll)); 1699162674Spiso if (t == NULL) 1700162674Spiso return (ENOMEM); 1701162674Spiso strncpy(t->name, p->name, DLL_LEN); 1702162674Spiso t->handle = handle; 1703162674Spiso if (attach_dll(t) == EEXIST) { 1704162674Spiso free(t); 1705164798Spiso fprintf(stderr, "dll conflict\n"); 1706162674Spiso return (EEXIST); 1707162674Spiso } 1708162674Spiso 1709162674Spiso m = dlsym(t->handle, "handlers"); 1710162674Spiso if ((error = dlerror()) != NULL) { 1711164798Spiso fprintf(stderr, "%s\n", error); 1712164798Spiso return (EINVAL); 1713164798Spiso } 1714162674Spiso 1715162674Spiso LibAliasAttachHandlers(m); 1716162674Spiso return (0); 1717162674Spiso} 1718162674Spiso 1719162674Spisoint 1720162674SpisoLibAliasUnLoadAllModule(void) 1721162674Spiso{ 1722162674Spiso struct dll *t; 1723162674Spiso struct proto_handler *p; 1724162674Spiso 1725162674Spiso /* Unload all modules then reload everything. */ 1726162674Spiso while ((p = first_handler()) != NULL) { 1727162674Spiso detach_handler(p); 1728162674Spiso } 1729162674Spiso while ((t = walk_dll_chain()) != NULL) { 1730162674Spiso dlclose(t->handle); 1731162674Spiso free(t); 1732162674Spiso } 1733162674Spiso return (1); 1734162674Spiso} 1735162674Spiso 1736162674Spiso#endif 1737164797Spiso 1738164797Spiso#ifdef _KERNEL 1739164797Spiso/* 1740165243Spiso * m_megapullup() - this function is a big hack. 1741165243Spiso * Thankfully, it's only used in ng_nat and ipfw+nat. 1742164797Spiso * 1743179478Smav * It allocates an mbuf with cluster and copies the specified part of the chain 1744179478Smav * into cluster, so that it is all contiguous and can be accessed via a plain 1745179478Smav * (char *) pointer. This is required, because libalias doesn't know how to 1746179478Smav * handle mbuf chains. 1747165243Spiso * 1748179478Smav * On success, m_megapullup returns an mbuf (possibly with cluster) containing 1749179478Smav * the input packet, on failure NULL. The input packet is always consumed. 1750164797Spiso */ 1751164797Spisostruct mbuf * 1752335474Saem_megapullup(struct mbuf *m, int len) 1753335474Sae{ 1754164797Spiso struct mbuf *mcl; 1755248416Sglebius 1756179478Smav if (len > m->m_pkthdr.len) 1757164797Spiso goto bad; 1758248416Sglebius 1759248416Sglebius if (m->m_next == NULL && M_WRITABLE(m)) 1760179478Smav return (m); 1761179478Smav 1762335474Sae if (len <= MJUMPAGESIZE) 1763335474Sae mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR); 1764335474Sae else if (len <= MJUM9BYTES) 1765335474Sae mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 1766335474Sae else if (len <= MJUM16BYTES) 1767335474Sae mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES); 1768335474Sae else 1769335474Sae goto bad; 1770179478Smav if (mcl == NULL) 1771179478Smav goto bad; 1772248416Sglebius m_align(mcl, len); 1773164797Spiso m_move_pkthdr(mcl, m); 1774179478Smav m_copydata(m, 0, len, mtod(mcl, caddr_t)); 1775179478Smav mcl->m_len = mcl->m_pkthdr.len = len; 1776164797Spiso m_freem(m); 1777248416Sglebius 1778164797Spiso return (mcl); 1779164797Spisobad: 1780164797Spiso m_freem(m); 1781164797Spiso return (NULL); 1782164797Spiso} 1783164797Spiso#endif 1784