2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 Alias.c provides supervisory control for the functions of the
32 packet aliasing software. It consists of routines to monitor
33 TCP connection state, protocol-specific aliasing routines,
34 fragment handling and the following outside world functional
35 interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
36 PacketAliasIn and PacketAliasOut.
38 The other C program files are briefly described. The data
39 structure framework which holds information needed to translate
40 packets is encapsulated in alias_db.c. Data is accessed by
41 function calls, so other segments of the program need not know
42 about the underlying data structures. Alias_ftp.c contains
43 special code for modifying the ftp PORT command used to establish
44 data connections, while alias_irc.c does the same for IRC
45 DCC. Alias_util.c contains a few utility routines.
47 Version 1.0 August, 1996 (cjm)
49 Version 1.1 August 20, 1996 (cjm)
50 PPP host accepts incoming connections for ports 0 to 1023.
51 (Gary Roberts pointed out the need to handle incoming
54 Version 1.2 September 7, 1996 (cjm)
55 Fragment handling error in alias_db.c corrected.
56 (Tom Torrance helped fix this problem.)
58 Version 1.4 September 16, 1996 (cjm)
59 - A more generalized method for handling incoming
60 connections, without the 0-1023 restriction, is
61 implemented in alias_db.c
62 - Improved ICMP support in alias.c. Traceroute
63 packet streams can now be correctly aliased.
64 - TCP connection closing logic simplified in
65 alias.c and now allows for additional 1 minute
66 "grace period" after FIN or RST is observed.
68 Version 1.5 September 17, 1996 (cjm)
69 Corrected error in handling incoming UDP packets with 0 checksum.
70 (Tom Torrance helped fix this problem.)
72 Version 1.6 September 18, 1996 (cjm)
73 Simplified ICMP aliasing scheme. Should now support
74 traceroute from Win95 as well as FreeBSD.
76 Version 1.7 January 9, 1997 (cjm)
77 - Out-of-order fragment handling.
78 - IP checksum error fixed for ftp transfers
80 - Integer return codes added to all
81 aliasing/de-aliasing functions.
82 - Some obsolete comments cleaned up.
83 - Differential checksum computations for
84 IP header (TCP, UDP and ICMP were already
87 Version 2.1 May 1997 (cjm)
88 - Added support for outgoing ICMP error
90 - Added two functions PacketAliasIn2()
91 and PacketAliasOut2() for dynamic address
92 control (e.g. round-robin allocation of
95 Version 2.2 July 1997 (cjm)
96 - Rationalized API function names to begin
98 - Eliminated PacketAliasIn2() and
99 PacketAliasOut2() as poorly conceived.
101 Version 2.3 Dec 1998 (dillon)
102 - Major bounds checking additions, see FreeBSD/CVS
104 Version 3.1 May, 2000 (salander)
105 - Added hooks to handle PPTP.
107 Version 3.2 July, 2000 (salander and satoh)
108 - Added PacketUnaliasOut routine.
109 - Added hooks to handle RTSP/RTP.
111 See HISTORY file for additional revisions.
114 #include <sys/types.h>
116 #include <netinet/in_systm.h>
117 #include <netinet/in.h>
118 #include <netinet/ip.h>
119 #include <netinet/ip_icmp.h>
120 #include <netinet/tcp.h>
121 #include <netinet/udp.h>
125 #include "alias_local.h"
128 #define NETBIOS_NS_PORT_NUMBER 137
129 #define NETBIOS_DGM_PORT_NUMBER 138
130 #define FTP_CONTROL_PORT_NUMBER 21
131 #define IRC_CONTROL_PORT_NUMBER_1 6667
132 #define IRC_CONTROL_PORT_NUMBER_2 6668
133 #define CUSEEME_PORT_NUMBER 7648
134 #define RTSP_CONTROL_PORT_NUMBER_1 554
135 #define RTSP_CONTROL_PORT_NUMBER_2 7070
136 #define TFTP_PORT_NUMBER 69
137 #define PPTP_CONTROL_PORT_NUMBER 1723
144 #if BYTE_ORDER == LITTLE_ENDIAN
145 uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
146 uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
148 uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
149 uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
154 /* TCP Handling Routines
156 TcpMonitorIn() -- These routines monitor TCP connections, and
157 TcpMonitorOut() delete a link when a connection is closed.
159 These routines look for SYN, FIN and RST flags to determine when TCP
160 connections open and close. When a TCP connection closes, the data
161 structure containing packet aliasing information is deleted after
165 /* Local prototypes */
166 static void TcpMonitorIn(struct ip *, struct alias_link *);
168 static void TcpMonitorOut(struct ip *, struct alias_link *);
172 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
176 tc = (struct tcphdr *)ip_next(pip);
178 switch (GetStateIn(lnk)) {
179 case ALIAS_TCP_STATE_NOT_CONNECTED:
180 if (tc->th_flags & TH_RST)
181 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
182 else if (tc->th_flags & TH_SYN)
183 SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
185 case ALIAS_TCP_STATE_CONNECTED:
186 if (tc->th_flags & (TH_FIN | TH_RST))
187 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
193 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
197 tc = (struct tcphdr *)ip_next(pip);
199 switch (GetStateOut(lnk)) {
200 case ALIAS_TCP_STATE_NOT_CONNECTED:
201 if (tc->th_flags & TH_RST)
202 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
203 else if (tc->th_flags & TH_SYN)
204 SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
206 case ALIAS_TCP_STATE_CONNECTED:
207 if (tc->th_flags & (TH_FIN | TH_RST))
208 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
217 /* Protocol Specific Packet Aliasing Routines
219 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
220 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
221 ProtoAliasIn(), ProtoAliasOut()
222 UdpAliasIn(), UdpAliasOut()
223 TcpAliasIn(), TcpAliasOut()
225 These routines handle protocol specific details of packet aliasing.
226 One may observe a certain amount of repetitive arithmetic in these
227 functions, the purpose of which is to compute a revised checksum
228 without actually summing over the entire data packet, which could be
229 unnecessarily time consuming.
231 The purpose of the packet aliasing routines is to replace the source
232 address of the outgoing packet and then correctly put it back for
233 any incoming packets. For TCP and UDP, ports are also re-mapped.
235 For ICMP echo/timestamp requests and replies, the following scheme
236 is used: the ID number is replaced by an alias for the outgoing
239 ICMP error messages are handled by looking at the IP fragment
240 in the data section of the message.
242 For TCP and UDP protocols, a port number is chosen for an outgoing
243 packet, and then incoming packets are identified by IP address and
244 port numbers. For TCP packets, there is additional logic in the event
245 that sequence and ACK numbers have been altered (as in the case for
246 FTP data port commands).
248 The port numbers used by the packet aliasing module are not true
249 ports in the Unix sense. No sockets are actually bound to ports.
250 They are more correctly thought of as placeholders.
252 All packets go through the aliasing mechanism, whether they come from
253 the gateway machine or other machines on a local area network.
257 /* Local prototypes */
258 static int IcmpAliasIn1(struct libalias *, struct ip *);
259 static int IcmpAliasIn2(struct libalias *, struct ip *);
260 static int IcmpAliasIn(struct libalias *, struct ip *);
262 static int IcmpAliasOut1(struct libalias *, struct ip *);
263 static int IcmpAliasOut2(struct libalias *, struct ip *);
264 static int IcmpAliasOut(struct libalias *, struct ip *, int create);
266 static int ProtoAliasIn(struct libalias *, struct ip *);
267 static int ProtoAliasOut(struct libalias *, struct ip *, int create);
269 static int UdpAliasIn(struct libalias *, struct ip *);
270 static int UdpAliasOut(struct libalias *, struct ip *, int create);
272 static int TcpAliasIn(struct libalias *, struct ip *);
273 static int TcpAliasOut(struct libalias *, struct ip *, int, int create);
277 IcmpAliasIn1(struct libalias *la, struct ip *pip)
280 De-alias incoming echo and timestamp replies.
281 Alias incoming echo and timestamp requests.
283 struct alias_link *lnk;
286 ic = (struct icmp *)ip_next(pip);
288 /* Get source address from ICMP data field and restore original data */
289 lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
294 original_id = GetOriginalPort(lnk);
296 /* Adjust ICMP checksum */
297 accumulate = ic->icmp_id;
298 accumulate -= original_id;
299 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
301 /* Put original sequence number back in */
302 ic->icmp_id = original_id;
304 /* Put original address back into IP header */
306 struct in_addr original_address;
308 original_address = GetOriginalAddress(lnk);
309 DifferentialChecksum(&pip->ip_sum,
310 &original_address, &pip->ip_dst, 2);
311 pip->ip_dst = original_address;
314 return (PKT_ALIAS_OK);
316 return (PKT_ALIAS_IGNORED);
320 IcmpAliasIn2(struct libalias *la, struct ip *pip)
323 Alias incoming ICMP error messages containing
324 IP header and first 64 bits of datagram.
327 struct icmp *ic, *ic2;
330 struct alias_link *lnk;
332 ic = (struct icmp *)ip_next(pip);
335 ud = (struct udphdr *)ip_next(ip);
336 tc = (struct tcphdr *)ip_next(ip);
337 ic2 = (struct icmp *)ip_next(ip);
339 if (ip->ip_p == IPPROTO_UDP)
340 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
341 ud->uh_dport, ud->uh_sport,
343 else if (ip->ip_p == IPPROTO_TCP)
344 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
345 tc->th_dport, tc->th_sport,
347 else if (ip->ip_p == IPPROTO_ICMP) {
348 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
349 lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
356 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
357 int accumulate, accumulate2;
358 struct in_addr original_address;
359 u_short original_port;
361 original_address = GetOriginalAddress(lnk);
362 original_port = GetOriginalPort(lnk);
364 /* Adjust ICMP checksum */
365 accumulate = twowords(&ip->ip_src);
366 accumulate -= twowords(&original_address);
367 accumulate += ud->uh_sport;
368 accumulate -= original_port;
369 accumulate2 = accumulate;
370 accumulate2 += ip->ip_sum;
371 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
372 accumulate2 -= ip->ip_sum;
373 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
375 /* Un-alias address in IP header */
376 DifferentialChecksum(&pip->ip_sum,
377 &original_address, &pip->ip_dst, 2);
378 pip->ip_dst = original_address;
380 /* Un-alias address and port number of original IP packet
381 fragment contained in ICMP data section */
382 ip->ip_src = original_address;
383 ud->uh_sport = original_port;
384 } else if (ip->ip_p == IPPROTO_ICMP) {
385 int accumulate, accumulate2;
386 struct in_addr original_address;
389 original_address = GetOriginalAddress(lnk);
390 original_id = GetOriginalPort(lnk);
392 /* Adjust ICMP checksum */
393 accumulate = twowords(&ip->ip_src);
394 accumulate -= twowords(&original_address);
395 accumulate += ic2->icmp_id;
396 accumulate -= original_id;
397 accumulate2 = accumulate;
398 accumulate2 += ip->ip_sum;
399 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
400 accumulate2 -= ip->ip_sum;
401 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
403 /* Un-alias address in IP header */
404 DifferentialChecksum(&pip->ip_sum,
405 &original_address, &pip->ip_dst, 2);
406 pip->ip_dst = original_address;
408 /* Un-alias address of original IP packet and sequence number of
409 embedded ICMP datagram */
410 ip->ip_src = original_address;
411 ic2->icmp_id = original_id;
413 return (PKT_ALIAS_OK);
415 return (PKT_ALIAS_IGNORED);
420 IcmpAliasIn(struct libalias *la, struct ip *pip)
425 /* Return if proxy-only mode is enabled */
426 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
427 return (PKT_ALIAS_OK);
429 ic = (struct icmp *)ip_next(pip);
431 iresult = PKT_ALIAS_IGNORED;
432 switch (ic->icmp_type) {
434 case ICMP_TSTAMPREPLY:
435 if (ic->icmp_code == 0) {
436 iresult = IcmpAliasIn1(la, pip);
440 case ICMP_SOURCEQUENCH:
443 iresult = IcmpAliasIn2(la, pip);
447 iresult = IcmpAliasIn1(la, pip);
455 IcmpAliasOut1(struct libalias *la, struct ip *pip)
458 Alias outgoing echo and timestamp requests.
459 De-alias outgoing echo and timestamp replies.
461 struct alias_link *lnk;
464 ic = (struct icmp *)ip_next(pip);
466 /* Save overwritten data for when echo packet returns */
467 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
472 alias_id = GetAliasPort(lnk);
474 /* Since data field is being modified, adjust ICMP checksum */
475 accumulate = ic->icmp_id;
476 accumulate -= alias_id;
477 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
479 /* Alias sequence number */
480 ic->icmp_id = alias_id;
482 /* Change source address */
484 struct in_addr alias_address;
486 alias_address = GetAliasAddress(lnk);
487 DifferentialChecksum(&pip->ip_sum,
488 &alias_address, &pip->ip_src, 2);
489 pip->ip_src = alias_address;
492 return (PKT_ALIAS_OK);
494 return (PKT_ALIAS_IGNORED);
499 IcmpAliasOut2(struct libalias *la, struct ip *pip)
502 Alias outgoing ICMP error messages containing
503 IP header and first 64 bits of datagram.
506 struct icmp *ic, *ic2;
509 struct alias_link *lnk;
511 ic = (struct icmp *)ip_next(pip);
514 ud = (struct udphdr *)ip_next(ip);
515 tc = (struct tcphdr *)ip_next(ip);
516 ic2 = (struct icmp *)ip_next(ip);
518 if (ip->ip_p == IPPROTO_UDP)
519 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
520 ud->uh_dport, ud->uh_sport,
522 else if (ip->ip_p == IPPROTO_TCP)
523 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
524 tc->th_dport, tc->th_sport,
526 else if (ip->ip_p == IPPROTO_ICMP) {
527 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
528 lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
535 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
537 struct in_addr alias_address;
540 alias_address = GetAliasAddress(lnk);
541 alias_port = GetAliasPort(lnk);
543 /* Adjust ICMP checksum */
544 accumulate = twowords(&ip->ip_dst);
545 accumulate -= twowords(&alias_address);
546 accumulate += ud->uh_dport;
547 accumulate -= alias_port;
548 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
551 * Alias address in IP header if it comes from the host
552 * the original TCP/UDP packet was destined for.
554 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
555 DifferentialChecksum(&pip->ip_sum,
556 &alias_address, &pip->ip_src, 2);
557 pip->ip_src = alias_address;
559 /* Alias address and port number of original IP packet
560 fragment contained in ICMP data section */
561 ip->ip_dst = alias_address;
562 ud->uh_dport = alias_port;
563 } else if (ip->ip_p == IPPROTO_ICMP) {
565 struct in_addr alias_address;
568 alias_address = GetAliasAddress(lnk);
569 alias_id = GetAliasPort(lnk);
571 /* Adjust ICMP checksum */
572 accumulate = twowords(&ip->ip_dst);
573 accumulate -= twowords(&alias_address);
574 accumulate += ic2->icmp_id;
575 accumulate -= alias_id;
576 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
579 * Alias address in IP header if it comes from the host
580 * the original ICMP message was destined for.
582 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
583 DifferentialChecksum(&pip->ip_sum,
584 &alias_address, &pip->ip_src, 2);
585 pip->ip_src = alias_address;
587 /* Alias address of original IP packet and sequence number of
588 embedded ICMP datagram */
589 ip->ip_dst = alias_address;
590 ic2->icmp_id = alias_id;
592 return (PKT_ALIAS_OK);
594 return (PKT_ALIAS_IGNORED);
599 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
606 /* Return if proxy-only mode is enabled */
607 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
608 return (PKT_ALIAS_OK);
610 ic = (struct icmp *)ip_next(pip);
612 iresult = PKT_ALIAS_IGNORED;
613 switch (ic->icmp_type) {
616 if (ic->icmp_code == 0) {
617 iresult = IcmpAliasOut1(la, pip);
621 case ICMP_SOURCEQUENCH:
624 iresult = IcmpAliasOut2(la, pip);
627 case ICMP_TSTAMPREPLY:
628 iresult = IcmpAliasOut1(la, pip);
636 ProtoAliasIn(struct libalias *la, struct ip *pip)
639 Handle incoming IP packets. The
640 only thing which is done in this case is to alias
641 the dest IP address of the packet to our inside
644 struct alias_link *lnk;
646 /* Return if proxy-only mode is enabled */
647 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
648 return (PKT_ALIAS_OK);
650 lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
652 struct in_addr original_address;
654 original_address = GetOriginalAddress(lnk);
656 /* Restore original IP address */
657 DifferentialChecksum(&pip->ip_sum,
658 &original_address, &pip->ip_dst, 2);
659 pip->ip_dst = original_address;
661 return (PKT_ALIAS_OK);
663 return (PKT_ALIAS_IGNORED);
668 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
671 Handle outgoing IP packets. The
672 only thing which is done in this case is to alias
673 the source IP address of the packet.
675 struct alias_link *lnk;
679 /* Return if proxy-only mode is enabled */
680 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
681 return (PKT_ALIAS_OK);
683 lnk = FindProtoOut(la, pip->ip_src, pip->ip_dst, pip->ip_p);
685 struct in_addr alias_address;
687 alias_address = GetAliasAddress(lnk);
689 /* Change source address */
690 DifferentialChecksum(&pip->ip_sum,
691 &alias_address, &pip->ip_src, 2);
692 pip->ip_src = alias_address;
694 return (PKT_ALIAS_OK);
696 return (PKT_ALIAS_IGNORED);
701 UdpAliasIn(struct libalias *la, struct ip *pip)
704 struct alias_link *lnk;
706 /* Return if proxy-only mode is enabled */
707 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
708 return (PKT_ALIAS_OK);
710 ud = (struct udphdr *)ip_next(pip);
712 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
713 ud->uh_sport, ud->uh_dport,
716 struct in_addr alias_address;
717 struct in_addr original_address;
722 alias_address = GetAliasAddress(lnk);
723 original_address = GetOriginalAddress(lnk);
724 alias_port = ud->uh_dport;
725 ud->uh_dport = GetOriginalPort(lnk);
727 /* Special processing for IP encoding protocols */
728 if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
729 AliasHandleCUSeeMeIn(la, pip, original_address);
730 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
731 else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
732 || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
733 r = AliasHandleUdpNbt(la, pip, lnk, &original_address, ud->uh_dport);
734 else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
735 || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
736 r = AliasHandleUdpNbtNS(la, pip, lnk, &alias_address, &alias_port,
737 &original_address, &ud->uh_dport);
739 /* If UDP checksum is not zero, then adjust since destination port */
740 /* is being unaliased and destination address is being altered. */
741 if (ud->uh_sum != 0) {
742 accumulate = alias_port;
743 accumulate -= ud->uh_dport;
744 accumulate += twowords(&alias_address);
745 accumulate -= twowords(&original_address);
746 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
748 /* Restore original IP address */
749 DifferentialChecksum(&pip->ip_sum,
750 &original_address, &pip->ip_dst, 2);
751 pip->ip_dst = original_address;
754 * If we cannot figure out the packet, ignore it.
757 return (PKT_ALIAS_IGNORED);
759 return (PKT_ALIAS_OK);
761 return (PKT_ALIAS_IGNORED);
765 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
768 struct alias_link *lnk;
770 /* Return if proxy-only mode is enabled */
771 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
772 return (PKT_ALIAS_OK);
774 ud = (struct udphdr *)ip_next(pip);
776 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
777 ud->uh_sport, ud->uh_dport,
778 IPPROTO_UDP, create);
781 struct in_addr alias_address;
783 alias_address = GetAliasAddress(lnk);
784 alias_port = GetAliasPort(lnk);
786 /* Special processing for IP encoding protocols */
787 if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
788 AliasHandleCUSeeMeOut(la, pip, lnk);
789 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
790 else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
791 || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
792 AliasHandleUdpNbt(la, pip, lnk, &alias_address, alias_port);
793 else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
794 || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
795 AliasHandleUdpNbtNS(la, pip, lnk, &pip->ip_src, &ud->uh_sport,
796 &alias_address, &alias_port);
798 * We don't know in advance what TID the TFTP server will choose,
799 * so we create a wilcard link (destination port is unspecified)
800 * that will match any TID from a given destination.
802 else if (ntohs(ud->uh_dport) == TFTP_PORT_NUMBER)
803 FindRtspOut(la, pip->ip_src, pip->ip_dst,
804 ud->uh_sport, alias_port, IPPROTO_UDP);
806 /* If UDP checksum is not zero, adjust since source port is */
807 /* being aliased and source address is being altered */
808 if (ud->uh_sum != 0) {
811 accumulate = ud->uh_sport;
812 accumulate -= alias_port;
813 accumulate += twowords(&pip->ip_src);
814 accumulate -= twowords(&alias_address);
815 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
817 /* Put alias port in UDP header */
818 ud->uh_sport = alias_port;
820 /* Change source address */
821 DifferentialChecksum(&pip->ip_sum,
822 &alias_address, &pip->ip_src, 2);
823 pip->ip_src = alias_address;
825 return (PKT_ALIAS_OK);
827 return (PKT_ALIAS_IGNORED);
833 TcpAliasIn(struct libalias *la, struct ip *pip)
836 struct alias_link *lnk;
838 tc = (struct tcphdr *)ip_next(pip);
840 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
841 tc->th_sport, tc->th_dport,
843 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
845 struct in_addr alias_address;
846 struct in_addr original_address;
847 struct in_addr proxy_address;
852 /* Special processing for IP encoding protocols */
853 if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
854 || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
855 AliasHandlePptpIn(la, pip, lnk);
856 else if (la->skinnyPort != 0 && (ntohs(tc->th_dport) == la->skinnyPort
857 || ntohs(tc->th_sport) == la->skinnyPort))
858 AliasHandleSkinny(la, pip, lnk);
860 alias_address = GetAliasAddress(lnk);
861 original_address = GetOriginalAddress(lnk);
862 proxy_address = GetProxyAddress(lnk);
863 alias_port = tc->th_dport;
864 tc->th_dport = GetOriginalPort(lnk);
865 proxy_port = GetProxyPort(lnk);
867 /* Adjust TCP checksum since destination port is being unaliased */
868 /* and destination port is being altered. */
869 accumulate = alias_port;
870 accumulate -= tc->th_dport;
871 accumulate += twowords(&alias_address);
872 accumulate -= twowords(&original_address);
874 /* If this is a proxy, then modify the TCP source port and
875 checksum accumulation */
876 if (proxy_port != 0) {
877 accumulate += tc->th_sport;
878 tc->th_sport = proxy_port;
879 accumulate -= tc->th_sport;
880 accumulate += twowords(&pip->ip_src);
881 accumulate -= twowords(&proxy_address);
883 /* See if ACK number needs to be modified */
884 if (GetAckModified(lnk) == 1) {
887 delta = GetDeltaAckIn(pip, lnk);
889 accumulate += twowords(&tc->th_ack);
890 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
891 accumulate -= twowords(&tc->th_ack);
894 ADJUST_CHECKSUM(accumulate, tc->th_sum);
896 /* Restore original IP address */
897 accumulate = twowords(&pip->ip_dst);
898 pip->ip_dst = original_address;
899 accumulate -= twowords(&pip->ip_dst);
901 /* If this is a transparent proxy packet, then modify the source
903 if (proxy_address.s_addr != 0) {
904 accumulate += twowords(&pip->ip_src);
905 pip->ip_src = proxy_address;
906 accumulate -= twowords(&pip->ip_src);
908 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
910 /* Monitor TCP connection state */
911 TcpMonitorIn(pip, lnk);
913 return (PKT_ALIAS_OK);
915 return (PKT_ALIAS_IGNORED);
919 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
923 u_short proxy_server_port;
924 struct in_addr dest_address;
925 struct in_addr proxy_server_address;
927 struct alias_link *lnk;
929 tc = (struct tcphdr *)ip_next(pip);
931 proxy_type = ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
933 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
934 return (PKT_ALIAS_OK);
936 /* If this is a transparent proxy, save original destination,
937 then alter the destination and adjust checksums */
938 dest_port = tc->th_dport;
939 dest_address = pip->ip_dst;
940 if (proxy_type != 0) {
943 accumulate = tc->th_dport;
944 tc->th_dport = proxy_server_port;
945 accumulate -= tc->th_dport;
946 accumulate += twowords(&pip->ip_dst);
947 accumulate -= twowords(&proxy_server_address);
948 ADJUST_CHECKSUM(accumulate, tc->th_sum);
950 accumulate = twowords(&pip->ip_dst);
951 pip->ip_dst = proxy_server_address;
952 accumulate -= twowords(&pip->ip_dst);
953 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
955 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
956 tc->th_sport, tc->th_dport,
957 IPPROTO_TCP, create);
959 return (PKT_ALIAS_IGNORED);
962 struct in_addr alias_address;
965 /* Save original destination address, if this is a proxy packet.
966 Also modify packet to include destination encoding. This may
967 change the size of IP header. */
968 if (proxy_type != 0) {
969 SetProxyPort(lnk, dest_port);
970 SetProxyAddress(lnk, dest_address);
971 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
972 tc = (struct tcphdr *)ip_next(pip);
974 /* Get alias address and port */
975 alias_port = GetAliasPort(lnk);
976 alias_address = GetAliasAddress(lnk);
978 /* Monitor TCP connection state */
979 TcpMonitorOut(pip, lnk);
981 /* Special processing for IP encoding protocols */
982 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
983 || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
984 AliasHandleFtpOut(la, pip, lnk, maxpacketsize);
985 else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
986 || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
987 AliasHandleIrcOut(la, pip, lnk, maxpacketsize);
988 else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
989 || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
990 || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
991 || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2)
992 AliasHandleRtspOut(la, pip, lnk, maxpacketsize);
993 else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
994 || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
995 AliasHandlePptpOut(la, pip, lnk);
996 else if (la->skinnyPort != 0 && (ntohs(tc->th_sport) == la->skinnyPort
997 || ntohs(tc->th_dport) == la->skinnyPort))
998 AliasHandleSkinny(la, pip, lnk);
1000 /* Adjust TCP checksum since source port is being aliased */
1001 /* and source address is being altered */
1002 accumulate = tc->th_sport;
1003 tc->th_sport = alias_port;
1004 accumulate -= tc->th_sport;
1005 accumulate += twowords(&pip->ip_src);
1006 accumulate -= twowords(&alias_address);
1008 /* Modify sequence number if necessary */
1009 if (GetAckModified(lnk) == 1) {
1012 delta = GetDeltaSeqOut(pip, lnk);
1014 accumulate += twowords(&tc->th_seq);
1015 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1016 accumulate -= twowords(&tc->th_seq);
1019 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1021 /* Change source address */
1022 accumulate = twowords(&pip->ip_src);
1023 pip->ip_src = alias_address;
1024 accumulate -= twowords(&pip->ip_src);
1025 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1027 return (PKT_ALIAS_OK);
1029 return (PKT_ALIAS_IGNORED);
1035 /* Fragment Handling
1040 The packet aliasing module has a limited ability for handling IP
1041 fragments. If the ICMP, TCP or UDP header is in the first fragment
1042 received, then the ID number of the IP packet is saved, and other
1043 fragments are identified according to their ID number and IP address
1044 they were sent from. Pointers to unresolved fragments can also be
1045 saved and recalled when a header fragment is seen.
1048 /* Local prototypes */
1049 static int FragmentIn(struct libalias *, struct ip *);
1050 static int FragmentOut(struct libalias *, struct ip *);
1054 FragmentIn(struct libalias *la, struct ip *pip)
1056 struct alias_link *lnk;
1058 lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1060 struct in_addr original_address;
1062 GetFragmentAddr(lnk, &original_address);
1063 DifferentialChecksum(&pip->ip_sum,
1064 &original_address, &pip->ip_dst, 2);
1065 pip->ip_dst = original_address;
1067 return (PKT_ALIAS_OK);
1069 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1074 FragmentOut(struct libalias *la, struct ip *pip)
1076 struct in_addr alias_address;
1078 alias_address = FindAliasAddress(la, pip->ip_src);
1079 DifferentialChecksum(&pip->ip_sum,
1080 &alias_address, &pip->ip_src, 2);
1081 pip->ip_src = alias_address;
1083 return (PKT_ALIAS_OK);
1091 /* Outside World Access
1093 PacketAliasSaveFragment()
1094 PacketAliasGetFragment()
1095 PacketAliasFragmentIn()
1100 (prototypes in alias.h)
1105 LibAliasSaveFragment(struct libalias *la, char *ptr)
1108 struct alias_link *lnk;
1111 pip = (struct ip *)ptr;
1112 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1113 iresult = PKT_ALIAS_ERROR;
1115 SetFragmentPtr(lnk, ptr);
1116 iresult = PKT_ALIAS_OK;
1123 LibAliasGetFragment(struct libalias *la, char *ptr)
1125 struct alias_link *lnk;
1129 pip = (struct ip *)ptr;
1130 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1132 GetFragmentPtr(lnk, &fptr);
1133 SetFragmentPtr(lnk, NULL);
1134 SetExpire(lnk, 0); /* Deletes link */
1144 LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly
1147 char *ptr_fragment /* Points to fragment which must be
1155 pip = (struct ip *)ptr;
1156 fpip = (struct ip *)ptr_fragment;
1158 DifferentialChecksum(&fpip->ip_sum,
1159 &pip->ip_dst, &fpip->ip_dst, 2);
1160 fpip->ip_dst = pip->ip_dst;
1165 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1167 struct in_addr alias_addr;
1171 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1172 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1173 iresult = PacketAliasOut(ptr, maxpacketsize);
1174 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1178 ClearCheckNewLink(la);
1179 pip = (struct ip *)ptr;
1180 alias_addr = pip->ip_dst;
1182 /* Defense against mangled packets */
1183 if (ntohs(pip->ip_len) > maxpacketsize
1184 || (pip->ip_hl << 2) > maxpacketsize)
1185 return (PKT_ALIAS_IGNORED);
1187 iresult = PKT_ALIAS_IGNORED;
1188 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1189 switch (pip->ip_p) {
1191 iresult = IcmpAliasIn(la, pip);
1194 iresult = UdpAliasIn(la, pip);
1197 iresult = TcpAliasIn(la, pip);
1200 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
1201 AliasHandlePptpGreIn(la, pip) == 0)
1202 iresult = PKT_ALIAS_OK;
1204 iresult = ProtoAliasIn(la, pip);
1207 iresult = ProtoAliasIn(la, pip);
1211 if (ntohs(pip->ip_off) & IP_MF) {
1212 struct alias_link *lnk;
1214 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1216 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1217 SetFragmentAddr(lnk, pip->ip_dst);
1219 iresult = PKT_ALIAS_ERROR;
1223 iresult = FragmentIn(la, pip);
1231 /* Unregistered address ranges */
1233 /* 10.0.0.0 -> 10.255.255.255 */
1234 #define UNREG_ADDR_A_LOWER 0x0a000000
1235 #define UNREG_ADDR_A_UPPER 0x0affffff
1237 /* 172.16.0.0 -> 172.31.255.255 */
1238 #define UNREG_ADDR_B_LOWER 0xac100000
1239 #define UNREG_ADDR_B_UPPER 0xac1fffff
1241 /* 192.168.0.0 -> 192.168.255.255 */
1242 #define UNREG_ADDR_C_LOWER 0xc0a80000
1243 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1246 LibAliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1247 int maxpacketsize /* How much the packet data may grow (FTP
1248 * and IRC inline changes) */
1251 return (LibAliasOutTry(la, ptr, maxpacketsize, 1));
1255 LibAliasOutTry(struct libalias *la, char *ptr, /* valid IP packet */
1256 int maxpacketsize, /* How much the packet data may grow (FTP
1257 * and IRC inline changes) */
1258 int create /* Create new entries ? */
1262 struct in_addr addr_save;
1265 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1266 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1267 iresult = PacketAliasIn(ptr, maxpacketsize);
1268 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1272 ClearCheckNewLink(la);
1273 pip = (struct ip *)ptr;
1275 /* Defense against mangled packets */
1276 if (ntohs(pip->ip_len) > maxpacketsize
1277 || (pip->ip_hl << 2) > maxpacketsize)
1278 return (PKT_ALIAS_IGNORED);
1280 addr_save = GetDefaultAliasAddress(la);
1281 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1286 addr = ntohl(pip->ip_src.s_addr);
1287 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1289 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1291 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1295 SetDefaultAliasAddress(la, pip->ip_src);
1297 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1298 SetDefaultAliasAddress(la, pip->ip_src);
1300 iresult = PKT_ALIAS_IGNORED;
1301 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1302 switch (pip->ip_p) {
1304 iresult = IcmpAliasOut(la, pip, create);
1307 iresult = UdpAliasOut(la, pip, create);
1310 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1313 if (AliasHandlePptpGreOut(la, pip) == 0)
1314 iresult = PKT_ALIAS_OK;
1316 iresult = ProtoAliasOut(la, pip, create);
1319 iresult = ProtoAliasOut(la, pip, create);
1323 iresult = FragmentOut(la, pip);
1326 SetDefaultAliasAddress(la, addr_save);
1331 LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1332 int maxpacketsize /* for error checking */
1339 struct alias_link *lnk;
1340 int iresult = PKT_ALIAS_IGNORED;
1342 pip = (struct ip *)ptr;
1344 /* Defense against mangled packets */
1345 if (ntohs(pip->ip_len) > maxpacketsize
1346 || (pip->ip_hl << 2) > maxpacketsize)
1349 ud = (struct udphdr *)ip_next(pip);
1350 tc = (struct tcphdr *)ip_next(pip);
1351 ic = (struct icmp *)ip_next(pip);
1354 if (pip->ip_p == IPPROTO_UDP)
1355 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1356 ud->uh_dport, ud->uh_sport,
1358 else if (pip->ip_p == IPPROTO_TCP)
1359 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1360 tc->th_dport, tc->th_sport,
1362 else if (pip->ip_p == IPPROTO_ICMP)
1363 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1367 /* Change it from an aliased packet to an unaliased packet */
1369 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1371 struct in_addr original_address;
1372 u_short original_port;
1374 original_address = GetOriginalAddress(lnk);
1375 original_port = GetOriginalPort(lnk);
1377 /* Adjust TCP/UDP checksum */
1378 accumulate = twowords(&pip->ip_src);
1379 accumulate -= twowords(&original_address);
1381 if (pip->ip_p == IPPROTO_UDP) {
1382 accumulate += ud->uh_sport;
1383 accumulate -= original_port;
1384 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1386 accumulate += tc->th_sport;
1387 accumulate -= original_port;
1388 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1391 /* Adjust IP checksum */
1392 DifferentialChecksum(&pip->ip_sum,
1393 &original_address, &pip->ip_src, 2);
1395 /* Un-alias source address and port number */
1396 pip->ip_src = original_address;
1397 if (pip->ip_p == IPPROTO_UDP)
1398 ud->uh_sport = original_port;
1400 tc->th_sport = original_port;
1402 iresult = PKT_ALIAS_OK;
1404 } else if (pip->ip_p == IPPROTO_ICMP) {
1407 struct in_addr original_address;
1408 u_short original_id;
1410 original_address = GetOriginalAddress(lnk);
1411 original_id = GetOriginalPort(lnk);
1413 /* Adjust ICMP checksum */
1414 accumulate = twowords(&pip->ip_src);
1415 accumulate -= twowords(&original_address);
1416 accumulate += ic->icmp_id;
1417 accumulate -= original_id;
1418 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1420 /* Adjust IP checksum */
1421 DifferentialChecksum(&pip->ip_sum,
1422 &original_address, &pip->ip_src, 2);
1424 /* Un-alias source address and port number */
1425 pip->ip_src = original_address;
1426 ic->icmp_id = original_id;
1428 iresult = PKT_ALIAS_OK;