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.
115 #include <sys/param.h>
117 #include <sys/types.h>
125 #include <netinet/in_systm.h>
126 #include <netinet/in.h>
127 #include <netinet/ip.h>
128 #include <netinet/ip_icmp.h>
129 #include <netinet/tcp.h>
130 #include <netinet/udp.h>
133 #include <netinet/libalias/alias.h>
134 #include <netinet/libalias/alias_local.h>
135 #include <netinet/libalias/alias_mod.h>
139 #include "alias_local.h"
140 #include "alias_mod.h"
148 #if BYTE_ORDER == LITTLE_ENDIAN
149 uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
150 uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
152 uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
153 uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
158 /* TCP Handling Routines
160 TcpMonitorIn() -- These routines monitor TCP connections, and
161 TcpMonitorOut() delete a link when a connection is closed.
163 These routines look for SYN, FIN and RST flags to determine when TCP
164 connections open and close. When a TCP connection closes, the data
165 structure containing packet aliasing information is deleted after
169 /* Local prototypes */
170 static void TcpMonitorIn(struct ip *, struct alias_link *);
172 static void TcpMonitorOut(struct ip *, struct alias_link *);
176 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
180 tc = (struct tcphdr *)ip_next(pip);
182 switch (GetStateIn(lnk)) {
183 case ALIAS_TCP_STATE_NOT_CONNECTED:
184 if (tc->th_flags & TH_RST)
185 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
186 else if (tc->th_flags & TH_SYN)
187 SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
189 case ALIAS_TCP_STATE_CONNECTED:
190 if (tc->th_flags & (TH_FIN | TH_RST))
191 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
197 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
201 tc = (struct tcphdr *)ip_next(pip);
203 switch (GetStateOut(lnk)) {
204 case ALIAS_TCP_STATE_NOT_CONNECTED:
205 if (tc->th_flags & TH_RST)
206 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
207 else if (tc->th_flags & TH_SYN)
208 SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
210 case ALIAS_TCP_STATE_CONNECTED:
211 if (tc->th_flags & (TH_FIN | TH_RST))
212 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
221 /* Protocol Specific Packet Aliasing Routines
223 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
224 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
225 ProtoAliasIn(), ProtoAliasOut()
226 UdpAliasIn(), UdpAliasOut()
227 TcpAliasIn(), TcpAliasOut()
229 These routines handle protocol specific details of packet aliasing.
230 One may observe a certain amount of repetitive arithmetic in these
231 functions, the purpose of which is to compute a revised checksum
232 without actually summing over the entire data packet, which could be
233 unnecessarily time consuming.
235 The purpose of the packet aliasing routines is to replace the source
236 address of the outgoing packet and then correctly put it back for
237 any incoming packets. For TCP and UDP, ports are also re-mapped.
239 For ICMP echo/timestamp requests and replies, the following scheme
240 is used: the ID number is replaced by an alias for the outgoing
243 ICMP error messages are handled by looking at the IP fragment
244 in the data section of the message.
246 For TCP and UDP protocols, a port number is chosen for an outgoing
247 packet, and then incoming packets are identified by IP address and
248 port numbers. For TCP packets, there is additional logic in the event
249 that sequence and ACK numbers have been altered (as in the case for
250 FTP data port commands).
252 The port numbers used by the packet aliasing module are not true
253 ports in the Unix sense. No sockets are actually bound to ports.
254 They are more correctly thought of as placeholders.
256 All packets go through the aliasing mechanism, whether they come from
257 the gateway machine or other machines on a local area network.
261 /* Local prototypes */
262 static int IcmpAliasIn1(struct libalias *, struct ip *);
263 static int IcmpAliasIn2(struct libalias *, struct ip *);
264 static int IcmpAliasIn(struct libalias *, struct ip *);
266 static int IcmpAliasOut1(struct libalias *, struct ip *, int create);
267 static int IcmpAliasOut2(struct libalias *, struct ip *);
268 static int IcmpAliasOut(struct libalias *, struct ip *, int create);
270 static int ProtoAliasIn(struct libalias *, struct ip *);
271 static int ProtoAliasOut(struct libalias *, struct ip *, int create);
273 static int UdpAliasIn(struct libalias *, struct ip *);
274 static int UdpAliasOut(struct libalias *, struct ip *, int create);
276 static int TcpAliasIn(struct libalias *, struct ip *);
277 static int TcpAliasOut(struct libalias *, struct ip *, int, int create);
281 IcmpAliasIn1(struct libalias *la, struct ip *pip)
284 De-alias incoming echo and timestamp replies.
285 Alias incoming echo and timestamp requests.
287 struct alias_link *lnk;
290 ic = (struct icmp *)ip_next(pip);
292 /* Get source address from ICMP data field and restore original data */
293 lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
298 original_id = GetOriginalPort(lnk);
300 /* Adjust ICMP checksum */
301 accumulate = ic->icmp_id;
302 accumulate -= original_id;
303 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
305 /* Put original sequence number back in */
306 ic->icmp_id = original_id;
308 /* Put original address back into IP header */
310 struct in_addr original_address;
312 original_address = GetOriginalAddress(lnk);
313 DifferentialChecksum(&pip->ip_sum,
314 &original_address, &pip->ip_dst, 2);
315 pip->ip_dst = original_address;
318 return (PKT_ALIAS_OK);
320 return (PKT_ALIAS_IGNORED);
324 IcmpAliasIn2(struct libalias *la, struct ip *pip)
327 Alias incoming ICMP error messages containing
328 IP header and first 64 bits of datagram.
331 struct icmp *ic, *ic2;
334 struct alias_link *lnk;
336 ic = (struct icmp *)ip_next(pip);
339 ud = (struct udphdr *)ip_next(ip);
340 tc = (struct tcphdr *)ip_next(ip);
341 ic2 = (struct icmp *)ip_next(ip);
343 if (ip->ip_p == IPPROTO_UDP)
344 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
345 ud->uh_dport, ud->uh_sport,
347 else if (ip->ip_p == IPPROTO_TCP)
348 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
349 tc->th_dport, tc->th_sport,
351 else if (ip->ip_p == IPPROTO_ICMP) {
352 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
353 lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
360 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
361 int accumulate, accumulate2;
362 struct in_addr original_address;
363 u_short original_port;
365 original_address = GetOriginalAddress(lnk);
366 original_port = GetOriginalPort(lnk);
368 /* Adjust ICMP checksum */
369 accumulate = twowords(&ip->ip_src);
370 accumulate -= twowords(&original_address);
371 accumulate += ud->uh_sport;
372 accumulate -= original_port;
373 accumulate2 = accumulate;
374 accumulate2 += ip->ip_sum;
375 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
376 accumulate2 -= ip->ip_sum;
377 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
379 /* Un-alias address in IP header */
380 DifferentialChecksum(&pip->ip_sum,
381 &original_address, &pip->ip_dst, 2);
382 pip->ip_dst = original_address;
384 /* Un-alias address and port number of original IP packet
385 fragment contained in ICMP data section */
386 ip->ip_src = original_address;
387 ud->uh_sport = original_port;
388 } else if (ip->ip_p == IPPROTO_ICMP) {
389 int accumulate, accumulate2;
390 struct in_addr original_address;
393 original_address = GetOriginalAddress(lnk);
394 original_id = GetOriginalPort(lnk);
396 /* Adjust ICMP checksum */
397 accumulate = twowords(&ip->ip_src);
398 accumulate -= twowords(&original_address);
399 accumulate += ic2->icmp_id;
400 accumulate -= original_id;
401 accumulate2 = accumulate;
402 accumulate2 += ip->ip_sum;
403 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
404 accumulate2 -= ip->ip_sum;
405 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
407 /* Un-alias address in IP header */
408 DifferentialChecksum(&pip->ip_sum,
409 &original_address, &pip->ip_dst, 2);
410 pip->ip_dst = original_address;
412 /* Un-alias address of original IP packet and sequence number of
413 embedded ICMP datagram */
414 ip->ip_src = original_address;
415 ic2->icmp_id = original_id;
417 return (PKT_ALIAS_OK);
419 return (PKT_ALIAS_IGNORED);
424 IcmpAliasIn(struct libalias *la, struct ip *pip)
429 /* Return if proxy-only mode is enabled */
430 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
431 return (PKT_ALIAS_OK);
433 ic = (struct icmp *)ip_next(pip);
435 iresult = PKT_ALIAS_IGNORED;
436 switch (ic->icmp_type) {
438 case ICMP_TSTAMPREPLY:
439 if (ic->icmp_code == 0) {
440 iresult = IcmpAliasIn1(la, pip);
444 case ICMP_SOURCEQUENCH:
447 iresult = IcmpAliasIn2(la, pip);
451 iresult = IcmpAliasIn1(la, pip);
459 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
462 Alias outgoing echo and timestamp requests.
463 De-alias outgoing echo and timestamp replies.
465 struct alias_link *lnk;
468 ic = (struct icmp *)ip_next(pip);
470 /* Save overwritten data for when echo packet returns */
471 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
476 alias_id = GetAliasPort(lnk);
478 /* Since data field is being modified, adjust ICMP checksum */
479 accumulate = ic->icmp_id;
480 accumulate -= alias_id;
481 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
483 /* Alias sequence number */
484 ic->icmp_id = alias_id;
486 /* Change source address */
488 struct in_addr alias_address;
490 alias_address = GetAliasAddress(lnk);
491 DifferentialChecksum(&pip->ip_sum,
492 &alias_address, &pip->ip_src, 2);
493 pip->ip_src = alias_address;
496 return (PKT_ALIAS_OK);
498 return (PKT_ALIAS_IGNORED);
503 IcmpAliasOut2(struct libalias *la, struct ip *pip)
506 Alias outgoing ICMP error messages containing
507 IP header and first 64 bits of datagram.
510 struct icmp *ic, *ic2;
513 struct alias_link *lnk;
515 ic = (struct icmp *)ip_next(pip);
518 ud = (struct udphdr *)ip_next(ip);
519 tc = (struct tcphdr *)ip_next(ip);
520 ic2 = (struct icmp *)ip_next(ip);
522 if (ip->ip_p == IPPROTO_UDP)
523 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
524 ud->uh_dport, ud->uh_sport,
526 else if (ip->ip_p == IPPROTO_TCP)
527 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
528 tc->th_dport, tc->th_sport,
530 else if (ip->ip_p == IPPROTO_ICMP) {
531 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
532 lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
539 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
541 struct in_addr alias_address;
544 alias_address = GetAliasAddress(lnk);
545 alias_port = GetAliasPort(lnk);
547 /* Adjust ICMP checksum */
548 accumulate = twowords(&ip->ip_dst);
549 accumulate -= twowords(&alias_address);
550 accumulate += ud->uh_dport;
551 accumulate -= alias_port;
552 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
555 * Alias address in IP header if it comes from the host
556 * the original TCP/UDP packet was destined for.
558 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
559 DifferentialChecksum(&pip->ip_sum,
560 &alias_address, &pip->ip_src, 2);
561 pip->ip_src = alias_address;
563 /* Alias address and port number of original IP packet
564 fragment contained in ICMP data section */
565 ip->ip_dst = alias_address;
566 ud->uh_dport = alias_port;
567 } else if (ip->ip_p == IPPROTO_ICMP) {
569 struct in_addr alias_address;
572 alias_address = GetAliasAddress(lnk);
573 alias_id = GetAliasPort(lnk);
575 /* Adjust ICMP checksum */
576 accumulate = twowords(&ip->ip_dst);
577 accumulate -= twowords(&alias_address);
578 accumulate += ic2->icmp_id;
579 accumulate -= alias_id;
580 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
583 * Alias address in IP header if it comes from the host
584 * the original ICMP message was destined for.
586 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
587 DifferentialChecksum(&pip->ip_sum,
588 &alias_address, &pip->ip_src, 2);
589 pip->ip_src = alias_address;
591 /* Alias address of original IP packet and sequence number of
592 embedded ICMP datagram */
593 ip->ip_dst = alias_address;
594 ic2->icmp_id = alias_id;
596 return (PKT_ALIAS_OK);
598 return (PKT_ALIAS_IGNORED);
603 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
610 /* Return if proxy-only mode is enabled */
611 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
612 return (PKT_ALIAS_OK);
614 ic = (struct icmp *)ip_next(pip);
616 iresult = PKT_ALIAS_IGNORED;
617 switch (ic->icmp_type) {
620 if (ic->icmp_code == 0) {
621 iresult = IcmpAliasOut1(la, pip, create);
625 case ICMP_SOURCEQUENCH:
628 iresult = IcmpAliasOut2(la, pip);
631 case ICMP_TSTAMPREPLY:
632 iresult = IcmpAliasOut1(la, pip, create);
640 ProtoAliasIn(struct libalias *la, struct ip *pip)
643 Handle incoming IP packets. The
644 only thing which is done in this case is to alias
645 the dest IP address of the packet to our inside
648 struct alias_link *lnk;
650 /* Return if proxy-only mode is enabled */
651 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
652 return (PKT_ALIAS_OK);
654 lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
656 struct in_addr original_address;
658 original_address = GetOriginalAddress(lnk);
660 /* Restore original IP address */
661 DifferentialChecksum(&pip->ip_sum,
662 &original_address, &pip->ip_dst, 2);
663 pip->ip_dst = original_address;
665 return (PKT_ALIAS_OK);
667 return (PKT_ALIAS_IGNORED);
672 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
675 Handle outgoing IP packets. The
676 only thing which is done in this case is to alias
677 the source IP address of the packet.
679 struct alias_link *lnk;
683 /* Return if proxy-only mode is enabled */
684 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
685 return (PKT_ALIAS_OK);
687 lnk = FindProtoOut(la, pip->ip_src, pip->ip_dst, pip->ip_p);
689 struct in_addr alias_address;
691 alias_address = GetAliasAddress(lnk);
693 /* Change source address */
694 DifferentialChecksum(&pip->ip_sum,
695 &alias_address, &pip->ip_src, 2);
696 pip->ip_src = alias_address;
698 return (PKT_ALIAS_OK);
700 return (PKT_ALIAS_IGNORED);
705 UdpAliasIn(struct libalias *la, struct ip *pip)
708 struct alias_link *lnk;
710 /* Return if proxy-only mode is enabled */
711 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
712 return (PKT_ALIAS_OK);
714 ud = (struct udphdr *)ip_next(pip);
716 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
717 ud->uh_sport, ud->uh_dport,
720 struct in_addr alias_address;
721 struct in_addr original_address;
725 struct alias_data ad = {
727 .oaddr = &original_address,
728 .aaddr = &alias_address,
729 .aport = &alias_port,
730 .sport = &ud->uh_sport,
731 .dport = &ud->uh_dport,
735 alias_address = GetAliasAddress(lnk);
736 original_address = GetOriginalAddress(lnk);
737 alias_port = ud->uh_dport;
738 ud->uh_dport = GetOriginalPort(lnk);
740 /* Walk out chain. */
741 error = find_handler(IN, UDP, la, pip, &ad);
743 /* If UDP checksum is not zero, then adjust since destination port */
744 /* is being unaliased and destination address is being altered. */
745 if (ud->uh_sum != 0) {
746 accumulate = alias_port;
747 accumulate -= ud->uh_dport;
748 accumulate += twowords(&alias_address);
749 accumulate -= twowords(&original_address);
750 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
752 /* Restore original IP address */
753 DifferentialChecksum(&pip->ip_sum,
754 &original_address, &pip->ip_dst, 2);
755 pip->ip_dst = original_address;
758 * If we cannot figure out the packet, ignore it.
761 return (PKT_ALIAS_IGNORED);
763 return (PKT_ALIAS_OK);
765 return (PKT_ALIAS_IGNORED);
769 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
772 struct alias_link *lnk;
775 /* Return if proxy-only mode is enabled */
776 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
777 return (PKT_ALIAS_OK);
779 ud = (struct udphdr *)ip_next(pip);
781 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
782 ud->uh_sport, ud->uh_dport,
783 IPPROTO_UDP, create);
786 struct in_addr alias_address;
787 struct alias_data ad = {
790 .aaddr = &alias_address,
791 .aport = &alias_port,
792 .sport = &ud->uh_sport,
793 .dport = &ud->uh_dport,
797 alias_address = GetAliasAddress(lnk);
798 alias_port = GetAliasPort(lnk);
800 /* Walk out chain. */
801 error = find_handler(OUT, UDP, la, pip, &ad);
803 /* If UDP checksum is not zero, adjust since source port is */
804 /* being aliased and source address is being altered */
805 if (ud->uh_sum != 0) {
808 accumulate = ud->uh_sport;
809 accumulate -= alias_port;
810 accumulate += twowords(&pip->ip_src);
811 accumulate -= twowords(&alias_address);
812 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
814 /* Put alias port in UDP header */
815 ud->uh_sport = alias_port;
817 /* Change source address */
818 DifferentialChecksum(&pip->ip_sum,
819 &alias_address, &pip->ip_src, 2);
820 pip->ip_src = alias_address;
822 return (PKT_ALIAS_OK);
824 return (PKT_ALIAS_IGNORED);
830 TcpAliasIn(struct libalias *la, struct ip *pip)
833 struct alias_link *lnk;
835 tc = (struct tcphdr *)ip_next(pip);
837 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
838 tc->th_sport, tc->th_dport,
840 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
842 struct in_addr alias_address;
843 struct in_addr original_address;
844 struct in_addr proxy_address;
847 int accumulate, error;
850 * The init of MANY vars is a bit below, but aliashandlepptpin
851 * seems to need the destination port that came within the
852 * packet and not the original one looks below [*].
855 struct alias_data ad = {
860 .sport = &tc->th_sport,
861 .dport = &tc->th_dport,
865 /* Walk out chain. */
866 error = find_handler(IN, TCP, la, pip, &ad);
868 alias_address = GetAliasAddress(lnk);
869 original_address = GetOriginalAddress(lnk);
870 proxy_address = GetProxyAddress(lnk);
871 alias_port = tc->th_dport;
872 tc->th_dport = GetOriginalPort(lnk);
873 proxy_port = GetProxyPort(lnk);
876 * Look above, if anyone is going to add find_handler AFTER
877 * this aliashandlepptpin/point, please redo alias_data too.
878 * Uncommenting the piece here below should be enough.
881 struct alias_data ad = {
883 .oaddr = &original_address,
884 .aaddr = &alias_address,
885 .aport = &alias_port,
886 .sport = &ud->uh_sport,
887 .dport = &ud->uh_dport,
891 /* Walk out chain. */
892 error = find_handler(la, pip, &ad);
894 printf("Protocol handler not found\n");
897 /* Adjust TCP checksum since destination port is being unaliased */
898 /* and destination port is being altered. */
899 accumulate = alias_port;
900 accumulate -= tc->th_dport;
901 accumulate += twowords(&alias_address);
902 accumulate -= twowords(&original_address);
904 /* If this is a proxy, then modify the TCP source port and
905 checksum accumulation */
906 if (proxy_port != 0) {
907 accumulate += tc->th_sport;
908 tc->th_sport = proxy_port;
909 accumulate -= tc->th_sport;
910 accumulate += twowords(&pip->ip_src);
911 accumulate -= twowords(&proxy_address);
913 /* See if ACK number needs to be modified */
914 if (GetAckModified(lnk) == 1) {
917 delta = GetDeltaAckIn(pip, lnk);
919 accumulate += twowords(&tc->th_ack);
920 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
921 accumulate -= twowords(&tc->th_ack);
924 ADJUST_CHECKSUM(accumulate, tc->th_sum);
926 /* Restore original IP address */
927 accumulate = twowords(&pip->ip_dst);
928 pip->ip_dst = original_address;
929 accumulate -= twowords(&pip->ip_dst);
931 /* If this is a transparent proxy packet, then modify the source
933 if (proxy_address.s_addr != 0) {
934 accumulate += twowords(&pip->ip_src);
935 pip->ip_src = proxy_address;
936 accumulate -= twowords(&pip->ip_src);
938 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
940 /* Monitor TCP connection state */
941 TcpMonitorIn(pip, lnk);
943 return (PKT_ALIAS_OK);
945 return (PKT_ALIAS_IGNORED);
949 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
951 int proxy_type, error;
953 u_short proxy_server_port;
954 struct in_addr dest_address;
955 struct in_addr proxy_server_address;
957 struct alias_link *lnk;
959 tc = (struct tcphdr *)ip_next(pip);
963 ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
967 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
968 return (PKT_ALIAS_OK);
970 /* If this is a transparent proxy, save original destination,
971 then alter the destination and adjust checksums */
972 dest_port = tc->th_dport;
973 dest_address = pip->ip_dst;
974 if (proxy_type != 0) {
977 accumulate = tc->th_dport;
978 tc->th_dport = proxy_server_port;
979 accumulate -= tc->th_dport;
980 accumulate += twowords(&pip->ip_dst);
981 accumulate -= twowords(&proxy_server_address);
982 ADJUST_CHECKSUM(accumulate, tc->th_sum);
984 accumulate = twowords(&pip->ip_dst);
985 pip->ip_dst = proxy_server_address;
986 accumulate -= twowords(&pip->ip_dst);
987 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
989 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
990 tc->th_sport, tc->th_dport,
991 IPPROTO_TCP, create);
993 return (PKT_ALIAS_IGNORED);
996 struct in_addr alias_address;
998 struct alias_data ad = {
1001 .aaddr = &alias_address,
1002 .aport = &alias_port,
1003 .sport = &tc->th_sport,
1004 .dport = &tc->th_dport,
1005 .maxpktsize = maxpacketsize
1008 /* Save original destination address, if this is a proxy packet.
1009 Also modify packet to include destination encoding. This may
1010 change the size of IP header. */
1011 if (proxy_type != 0) {
1012 SetProxyPort(lnk, dest_port);
1013 SetProxyAddress(lnk, dest_address);
1014 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1015 tc = (struct tcphdr *)ip_next(pip);
1017 /* Get alias address and port */
1018 alias_port = GetAliasPort(lnk);
1019 alias_address = GetAliasAddress(lnk);
1021 /* Monitor TCP connection state */
1022 TcpMonitorOut(pip, lnk);
1024 /* Walk out chain. */
1025 error = find_handler(OUT, TCP, la, pip, &ad);
1027 /* Adjust TCP checksum since source port is being aliased */
1028 /* and source address is being altered */
1029 accumulate = tc->th_sport;
1030 tc->th_sport = alias_port;
1031 accumulate -= tc->th_sport;
1032 accumulate += twowords(&pip->ip_src);
1033 accumulate -= twowords(&alias_address);
1035 /* Modify sequence number if necessary */
1036 if (GetAckModified(lnk) == 1) {
1039 delta = GetDeltaSeqOut(pip, lnk);
1041 accumulate += twowords(&tc->th_seq);
1042 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1043 accumulate -= twowords(&tc->th_seq);
1046 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1048 /* Change source address */
1049 accumulate = twowords(&pip->ip_src);
1050 pip->ip_src = alias_address;
1051 accumulate -= twowords(&pip->ip_src);
1052 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1054 return (PKT_ALIAS_OK);
1056 return (PKT_ALIAS_IGNORED);
1062 /* Fragment Handling
1067 The packet aliasing module has a limited ability for handling IP
1068 fragments. If the ICMP, TCP or UDP header is in the first fragment
1069 received, then the ID number of the IP packet is saved, and other
1070 fragments are identified according to their ID number and IP address
1071 they were sent from. Pointers to unresolved fragments can also be
1072 saved and recalled when a header fragment is seen.
1075 /* Local prototypes */
1076 static int FragmentIn(struct libalias *, struct ip *);
1077 static int FragmentOut(struct libalias *, struct ip *);
1081 FragmentIn(struct libalias *la, struct ip *pip)
1083 struct alias_link *lnk;
1085 lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1087 struct in_addr original_address;
1089 GetFragmentAddr(lnk, &original_address);
1090 DifferentialChecksum(&pip->ip_sum,
1091 &original_address, &pip->ip_dst, 2);
1092 pip->ip_dst = original_address;
1094 return (PKT_ALIAS_OK);
1096 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1101 FragmentOut(struct libalias *la, struct ip *pip)
1103 struct in_addr alias_address;
1105 alias_address = FindAliasAddress(la, pip->ip_src);
1106 DifferentialChecksum(&pip->ip_sum,
1107 &alias_address, &pip->ip_src, 2);
1108 pip->ip_src = alias_address;
1110 return (PKT_ALIAS_OK);
1118 /* Outside World Access
1120 PacketAliasSaveFragment()
1121 PacketAliasGetFragment()
1122 PacketAliasFragmentIn()
1127 (prototypes in alias.h)
1132 LibAliasSaveFragment(struct libalias *la, char *ptr)
1135 struct alias_link *lnk;
1138 pip = (struct ip *)ptr;
1139 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1140 iresult = PKT_ALIAS_ERROR;
1142 SetFragmentPtr(lnk, ptr);
1143 iresult = PKT_ALIAS_OK;
1150 LibAliasGetFragment(struct libalias *la, char *ptr)
1152 struct alias_link *lnk;
1156 pip = (struct ip *)ptr;
1157 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1159 GetFragmentPtr(lnk, &fptr);
1160 SetFragmentPtr(lnk, NULL);
1161 SetExpire(lnk, 0); /* Deletes link */
1171 LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly
1174 char *ptr_fragment /* Points to fragment which must be
1182 pip = (struct ip *)ptr;
1183 fpip = (struct ip *)ptr_fragment;
1185 DifferentialChecksum(&fpip->ip_sum,
1186 &pip->ip_dst, &fpip->ip_dst, 2);
1187 fpip->ip_dst = pip->ip_dst;
1192 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1194 struct in_addr alias_addr;
1198 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1199 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1200 iresult = LibAliasOut(la, ptr, maxpacketsize);
1201 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1205 ClearCheckNewLink(la);
1206 pip = (struct ip *)ptr;
1207 alias_addr = pip->ip_dst;
1209 /* Defense against mangled packets */
1210 if (ntohs(pip->ip_len) > maxpacketsize
1211 || (pip->ip_hl << 2) > maxpacketsize)
1212 return (PKT_ALIAS_IGNORED);
1214 iresult = PKT_ALIAS_IGNORED;
1215 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1216 switch (pip->ip_p) {
1218 iresult = IcmpAliasIn(la, pip);
1221 iresult = UdpAliasIn(la, pip);
1224 iresult = TcpAliasIn(la, pip);
1228 struct alias_data ad = {
1238 /* Walk out chain. */
1239 error = find_handler(IN, IP, la, pip, &ad);
1241 iresult = PKT_ALIAS_OK;
1243 iresult = ProtoAliasIn(la, pip);
1247 iresult = ProtoAliasIn(la, pip);
1251 if (ntohs(pip->ip_off) & IP_MF) {
1252 struct alias_link *lnk;
1254 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1256 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1257 SetFragmentAddr(lnk, pip->ip_dst);
1259 iresult = PKT_ALIAS_ERROR;
1263 iresult = FragmentIn(la, pip);
1271 /* Unregistered address ranges */
1273 /* 10.0.0.0 -> 10.255.255.255 */
1274 #define UNREG_ADDR_A_LOWER 0x0a000000
1275 #define UNREG_ADDR_A_UPPER 0x0affffff
1277 /* 172.16.0.0 -> 172.31.255.255 */
1278 #define UNREG_ADDR_B_LOWER 0xac100000
1279 #define UNREG_ADDR_B_UPPER 0xac1fffff
1281 /* 192.168.0.0 -> 192.168.255.255 */
1282 #define UNREG_ADDR_C_LOWER 0xc0a80000
1283 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1286 LibAliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1287 int maxpacketsize /* How much the packet data may grow (FTP
1288 * and IRC inline changes) */
1291 return (LibAliasOutTry(la, ptr, maxpacketsize, 1));
1295 LibAliasOutTry(struct libalias *la, char *ptr, /* valid IP packet */
1296 int maxpacketsize, /* How much the packet data may grow (FTP
1297 * and IRC inline changes) */
1298 int create /* Create new entries ? */
1302 struct in_addr addr_save;
1305 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1306 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1307 iresult = LibAliasIn(la, ptr, maxpacketsize);
1308 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1312 ClearCheckNewLink(la);
1313 pip = (struct ip *)ptr;
1315 /* Defense against mangled packets */
1316 if (ntohs(pip->ip_len) > maxpacketsize
1317 || (pip->ip_hl << 2) > maxpacketsize)
1318 return (PKT_ALIAS_IGNORED);
1320 addr_save = GetDefaultAliasAddress(la);
1321 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1326 addr = ntohl(pip->ip_src.s_addr);
1327 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1329 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1331 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1335 SetDefaultAliasAddress(la, pip->ip_src);
1337 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1338 SetDefaultAliasAddress(la, pip->ip_src);
1340 iresult = PKT_ALIAS_IGNORED;
1341 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1342 switch (pip->ip_p) {
1344 iresult = IcmpAliasOut(la, pip, create);
1347 iresult = UdpAliasOut(la, pip, create);
1350 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1354 struct alias_data ad = {
1363 /* Walk out chain. */
1364 error = find_handler(OUT, IP, la, pip, &ad);
1366 iresult = PKT_ALIAS_OK;
1368 iresult = ProtoAliasOut(la, pip, create);
1372 iresult = ProtoAliasOut(la, pip, create);
1376 iresult = FragmentOut(la, pip);
1379 SetDefaultAliasAddress(la, addr_save);
1384 LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1385 int maxpacketsize /* for error checking */
1392 struct alias_link *lnk;
1393 int iresult = PKT_ALIAS_IGNORED;
1395 pip = (struct ip *)ptr;
1397 /* Defense against mangled packets */
1398 if (ntohs(pip->ip_len) > maxpacketsize
1399 || (pip->ip_hl << 2) > maxpacketsize)
1402 ud = (struct udphdr *)ip_next(pip);
1403 tc = (struct tcphdr *)ip_next(pip);
1404 ic = (struct icmp *)ip_next(pip);
1407 if (pip->ip_p == IPPROTO_UDP)
1408 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1409 ud->uh_dport, ud->uh_sport,
1411 else if (pip->ip_p == IPPROTO_TCP)
1412 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1413 tc->th_dport, tc->th_sport,
1415 else if (pip->ip_p == IPPROTO_ICMP)
1416 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1420 /* Change it from an aliased packet to an unaliased packet */
1422 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1424 struct in_addr original_address;
1425 u_short original_port;
1427 original_address = GetOriginalAddress(lnk);
1428 original_port = GetOriginalPort(lnk);
1430 /* Adjust TCP/UDP checksum */
1431 accumulate = twowords(&pip->ip_src);
1432 accumulate -= twowords(&original_address);
1434 if (pip->ip_p == IPPROTO_UDP) {
1435 accumulate += ud->uh_sport;
1436 accumulate -= original_port;
1437 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1439 accumulate += tc->th_sport;
1440 accumulate -= original_port;
1441 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1444 /* Adjust IP checksum */
1445 DifferentialChecksum(&pip->ip_sum,
1446 &original_address, &pip->ip_src, 2);
1448 /* Un-alias source address and port number */
1449 pip->ip_src = original_address;
1450 if (pip->ip_p == IPPROTO_UDP)
1451 ud->uh_sport = original_port;
1453 tc->th_sport = original_port;
1455 iresult = PKT_ALIAS_OK;
1457 } else if (pip->ip_p == IPPROTO_ICMP) {
1460 struct in_addr original_address;
1461 u_short original_id;
1463 original_address = GetOriginalAddress(lnk);
1464 original_id = GetOriginalPort(lnk);
1466 /* Adjust ICMP checksum */
1467 accumulate = twowords(&pip->ip_src);
1468 accumulate -= twowords(&original_address);
1469 accumulate += ic->icmp_id;
1470 accumulate -= original_id;
1471 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1473 /* Adjust IP checksum */
1474 DifferentialChecksum(&pip->ip_sum,
1475 &original_address, &pip->ip_src, 2);
1477 /* Un-alias source address and port number */
1478 pip->ip_src = original_address;
1479 ic->icmp_id = original_id;
1481 iresult = PKT_ALIAS_OK;
1491 LibAliasRefreshModules(void)
1493 char buf[256], conf[] = "/etc/libalias.conf";
1497 fd = fopen(conf, "r");
1499 err(1, "fopen(%s)", conf);
1501 LibAliasUnLoadAllModule();
1504 fgets(buf, 256, fd);
1509 buf[len - 1] = '\0';
1510 printf("Loading %s\n", buf);
1511 LibAliasLoadModule(buf);
1518 LibAliasLoadModule(char *path)
1522 struct proto_handler *m;
1526 handle = dlopen (path, RTLD_LAZY);
1528 fputs (dlerror(), stderr);
1532 p = dlsym(handle, "alias_mod");
1533 if ((error = dlerror()) != NULL) {
1534 fputs(error, stderr);
1538 t = malloc(sizeof(struct dll));
1541 strncpy(t->name, p->name, DLL_LEN);
1543 if (attach_dll(t) == EEXIST) {
1545 fputs("dll conflict", stderr);
1549 m = dlsym(t->handle, "handlers");
1550 if ((error = dlerror()) != NULL) {
1551 fputs(error, stderr);
1555 LibAliasAttachHandlers(m);
1560 LibAliasUnLoadAllModule(void)
1563 struct proto_handler *p;
1565 /* Unload all modules then reload everything. */
1566 while ((p = first_handler()) != NULL) {
1569 while ((t = walk_dll_chain()) != NULL) {