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>
116 #include <sys/systm.h>
117 #include <sys/mbuf.h>
119 #include <sys/types.h>
128 #include <netinet/in_systm.h>
129 #include <netinet/in.h>
130 #include <netinet/ip.h>
131 #include <netinet/ip_icmp.h>
132 #include <netinet/tcp.h>
133 #include <netinet/udp.h>
136 #include <netinet/libalias/alias.h>
137 #include <netinet/libalias/alias_local.h>
138 #include <netinet/libalias/alias_mod.h>
142 #include "alias_local.h"
143 #include "alias_mod.h"
151 #if BYTE_ORDER == LITTLE_ENDIAN
152 uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
153 uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
155 uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
156 uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
161 /* TCP Handling Routines
163 TcpMonitorIn() -- These routines monitor TCP connections, and
164 TcpMonitorOut() delete a link when a connection is closed.
166 These routines look for SYN, FIN and RST flags to determine when TCP
167 connections open and close. When a TCP connection closes, the data
168 structure containing packet aliasing information is deleted after
172 /* Local prototypes */
173 static void TcpMonitorIn(struct ip *, struct alias_link *);
175 static void TcpMonitorOut(struct ip *, struct alias_link *);
179 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
183 tc = (struct tcphdr *)ip_next(pip);
185 switch (GetStateIn(lnk)) {
186 case ALIAS_TCP_STATE_NOT_CONNECTED:
187 if (tc->th_flags & TH_RST)
188 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
189 else if (tc->th_flags & TH_SYN)
190 SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
192 case ALIAS_TCP_STATE_CONNECTED:
193 if (tc->th_flags & (TH_FIN | TH_RST))
194 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
200 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
204 tc = (struct tcphdr *)ip_next(pip);
206 switch (GetStateOut(lnk)) {
207 case ALIAS_TCP_STATE_NOT_CONNECTED:
208 if (tc->th_flags & TH_RST)
209 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
210 else if (tc->th_flags & TH_SYN)
211 SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
213 case ALIAS_TCP_STATE_CONNECTED:
214 if (tc->th_flags & (TH_FIN | TH_RST))
215 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
224 /* Protocol Specific Packet Aliasing Routines
226 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
227 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
228 ProtoAliasIn(), ProtoAliasOut()
229 UdpAliasIn(), UdpAliasOut()
230 TcpAliasIn(), TcpAliasOut()
232 These routines handle protocol specific details of packet aliasing.
233 One may observe a certain amount of repetitive arithmetic in these
234 functions, the purpose of which is to compute a revised checksum
235 without actually summing over the entire data packet, which could be
236 unnecessarily time consuming.
238 The purpose of the packet aliasing routines is to replace the source
239 address of the outgoing packet and then correctly put it back for
240 any incoming packets. For TCP and UDP, ports are also re-mapped.
242 For ICMP echo/timestamp requests and replies, the following scheme
243 is used: the ID number is replaced by an alias for the outgoing
246 ICMP error messages are handled by looking at the IP fragment
247 in the data section of the message.
249 For TCP and UDP protocols, a port number is chosen for an outgoing
250 packet, and then incoming packets are identified by IP address and
251 port numbers. For TCP packets, there is additional logic in the event
252 that sequence and ACK numbers have been altered (as in the case for
253 FTP data port commands).
255 The port numbers used by the packet aliasing module are not true
256 ports in the Unix sense. No sockets are actually bound to ports.
257 They are more correctly thought of as placeholders.
259 All packets go through the aliasing mechanism, whether they come from
260 the gateway machine or other machines on a local area network.
264 /* Local prototypes */
265 static int IcmpAliasIn1(struct libalias *, struct ip *);
266 static int IcmpAliasIn2(struct libalias *, struct ip *);
267 static int IcmpAliasIn(struct libalias *, struct ip *);
269 static int IcmpAliasOut1(struct libalias *, struct ip *, int create);
270 static int IcmpAliasOut2(struct libalias *, struct ip *);
271 static int IcmpAliasOut(struct libalias *, struct ip *, int create);
273 static int ProtoAliasIn(struct libalias *, struct ip *);
274 static int ProtoAliasOut(struct libalias *, struct ip *, int create);
276 static int UdpAliasIn(struct libalias *, struct ip *);
277 static int UdpAliasOut(struct libalias *, struct ip *, int create);
279 static int TcpAliasIn(struct libalias *, struct ip *);
280 static int TcpAliasOut(struct libalias *, struct ip *, int, int create);
284 IcmpAliasIn1(struct libalias *la, struct ip *pip)
287 LIBALIAS_LOCK_ASSERT(la);
289 De-alias incoming echo and timestamp replies.
290 Alias incoming echo and timestamp requests.
292 struct alias_link *lnk;
295 ic = (struct icmp *)ip_next(pip);
297 /* Get source address from ICMP data field and restore original data */
298 lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
303 original_id = GetOriginalPort(lnk);
305 /* Adjust ICMP checksum */
306 accumulate = ic->icmp_id;
307 accumulate -= original_id;
308 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
310 /* Put original sequence number back in */
311 ic->icmp_id = original_id;
313 /* Put original address back into IP header */
315 struct in_addr original_address;
317 original_address = GetOriginalAddress(lnk);
318 DifferentialChecksum(&pip->ip_sum,
319 &original_address, &pip->ip_dst, 2);
320 pip->ip_dst = original_address;
323 return (PKT_ALIAS_OK);
325 return (PKT_ALIAS_IGNORED);
329 IcmpAliasIn2(struct libalias *la, struct ip *pip)
332 LIBALIAS_LOCK_ASSERT(la);
334 Alias incoming ICMP error messages containing
335 IP header and first 64 bits of datagram.
338 struct icmp *ic, *ic2;
341 struct alias_link *lnk;
343 ic = (struct icmp *)ip_next(pip);
346 ud = (struct udphdr *)ip_next(ip);
347 tc = (struct tcphdr *)ip_next(ip);
348 ic2 = (struct icmp *)ip_next(ip);
350 if (ip->ip_p == IPPROTO_UDP)
351 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
352 ud->uh_dport, ud->uh_sport,
354 else if (ip->ip_p == IPPROTO_TCP)
355 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
356 tc->th_dport, tc->th_sport,
358 else if (ip->ip_p == IPPROTO_ICMP) {
359 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
360 lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
367 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
368 int accumulate, accumulate2;
369 struct in_addr original_address;
370 u_short original_port;
372 original_address = GetOriginalAddress(lnk);
373 original_port = GetOriginalPort(lnk);
375 /* Adjust ICMP checksum */
376 accumulate = twowords(&ip->ip_src);
377 accumulate -= twowords(&original_address);
378 accumulate += ud->uh_sport;
379 accumulate -= original_port;
380 accumulate2 = accumulate;
381 accumulate2 += ip->ip_sum;
382 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
383 accumulate2 -= ip->ip_sum;
384 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
386 /* Un-alias address in IP header */
387 DifferentialChecksum(&pip->ip_sum,
388 &original_address, &pip->ip_dst, 2);
389 pip->ip_dst = original_address;
391 /* Un-alias address and port number of original IP packet
392 fragment contained in ICMP data section */
393 ip->ip_src = original_address;
394 ud->uh_sport = original_port;
395 } else if (ip->ip_p == IPPROTO_ICMP) {
396 int accumulate, accumulate2;
397 struct in_addr original_address;
400 original_address = GetOriginalAddress(lnk);
401 original_id = GetOriginalPort(lnk);
403 /* Adjust ICMP checksum */
404 accumulate = twowords(&ip->ip_src);
405 accumulate -= twowords(&original_address);
406 accumulate += ic2->icmp_id;
407 accumulate -= original_id;
408 accumulate2 = accumulate;
409 accumulate2 += ip->ip_sum;
410 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
411 accumulate2 -= ip->ip_sum;
412 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
414 /* Un-alias address in IP header */
415 DifferentialChecksum(&pip->ip_sum,
416 &original_address, &pip->ip_dst, 2);
417 pip->ip_dst = original_address;
419 /* Un-alias address of original IP packet and sequence number of
420 embedded ICMP datagram */
421 ip->ip_src = original_address;
422 ic2->icmp_id = original_id;
424 return (PKT_ALIAS_OK);
426 return (PKT_ALIAS_IGNORED);
431 IcmpAliasIn(struct libalias *la, struct ip *pip)
436 LIBALIAS_LOCK_ASSERT(la);
437 /* Return if proxy-only mode is enabled */
438 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
439 return (PKT_ALIAS_OK);
441 ic = (struct icmp *)ip_next(pip);
443 iresult = PKT_ALIAS_IGNORED;
444 switch (ic->icmp_type) {
446 case ICMP_TSTAMPREPLY:
447 if (ic->icmp_code == 0) {
448 iresult = IcmpAliasIn1(la, pip);
452 case ICMP_SOURCEQUENCH:
455 iresult = IcmpAliasIn2(la, pip);
459 iresult = IcmpAliasIn1(la, pip);
467 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
470 Alias outgoing echo and timestamp requests.
471 De-alias outgoing echo and timestamp replies.
473 struct alias_link *lnk;
476 LIBALIAS_LOCK_ASSERT(la);
477 ic = (struct icmp *)ip_next(pip);
479 /* Save overwritten data for when echo packet returns */
480 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
485 alias_id = GetAliasPort(lnk);
487 /* Since data field is being modified, adjust ICMP checksum */
488 accumulate = ic->icmp_id;
489 accumulate -= alias_id;
490 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
492 /* Alias sequence number */
493 ic->icmp_id = alias_id;
495 /* Change source address */
497 struct in_addr alias_address;
499 alias_address = GetAliasAddress(lnk);
500 DifferentialChecksum(&pip->ip_sum,
501 &alias_address, &pip->ip_src, 2);
502 pip->ip_src = alias_address;
505 return (PKT_ALIAS_OK);
507 return (PKT_ALIAS_IGNORED);
512 IcmpAliasOut2(struct libalias *la, struct ip *pip)
515 Alias outgoing ICMP error messages containing
516 IP header and first 64 bits of datagram.
519 struct icmp *ic, *ic2;
522 struct alias_link *lnk;
524 LIBALIAS_LOCK_ASSERT(la);
525 ic = (struct icmp *)ip_next(pip);
528 ud = (struct udphdr *)ip_next(ip);
529 tc = (struct tcphdr *)ip_next(ip);
530 ic2 = (struct icmp *)ip_next(ip);
532 if (ip->ip_p == IPPROTO_UDP)
533 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
534 ud->uh_dport, ud->uh_sport,
536 else if (ip->ip_p == IPPROTO_TCP)
537 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
538 tc->th_dport, tc->th_sport,
540 else if (ip->ip_p == IPPROTO_ICMP) {
541 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
542 lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
549 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
551 struct in_addr alias_address;
554 alias_address = GetAliasAddress(lnk);
555 alias_port = GetAliasPort(lnk);
557 /* Adjust ICMP checksum */
558 accumulate = twowords(&ip->ip_dst);
559 accumulate -= twowords(&alias_address);
560 accumulate += ud->uh_dport;
561 accumulate -= alias_port;
562 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
565 * Alias address in IP header if it comes from the host
566 * the original TCP/UDP packet was destined for.
568 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
569 DifferentialChecksum(&pip->ip_sum,
570 &alias_address, &pip->ip_src, 2);
571 pip->ip_src = alias_address;
573 /* Alias address and port number of original IP packet
574 fragment contained in ICMP data section */
575 ip->ip_dst = alias_address;
576 ud->uh_dport = alias_port;
577 } else if (ip->ip_p == IPPROTO_ICMP) {
579 struct in_addr alias_address;
582 alias_address = GetAliasAddress(lnk);
583 alias_id = GetAliasPort(lnk);
585 /* Adjust ICMP checksum */
586 accumulate = twowords(&ip->ip_dst);
587 accumulate -= twowords(&alias_address);
588 accumulate += ic2->icmp_id;
589 accumulate -= alias_id;
590 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
593 * Alias address in IP header if it comes from the host
594 * the original ICMP message was destined for.
596 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
597 DifferentialChecksum(&pip->ip_sum,
598 &alias_address, &pip->ip_src, 2);
599 pip->ip_src = alias_address;
601 /* Alias address of original IP packet and sequence number of
602 embedded ICMP datagram */
603 ip->ip_dst = alias_address;
604 ic2->icmp_id = alias_id;
606 return (PKT_ALIAS_OK);
608 return (PKT_ALIAS_IGNORED);
613 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
618 LIBALIAS_LOCK_ASSERT(la);
621 /* Return if proxy-only mode is enabled */
622 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
623 return (PKT_ALIAS_OK);
625 ic = (struct icmp *)ip_next(pip);
627 iresult = PKT_ALIAS_IGNORED;
628 switch (ic->icmp_type) {
631 if (ic->icmp_code == 0) {
632 iresult = IcmpAliasOut1(la, pip, create);
636 case ICMP_SOURCEQUENCH:
639 iresult = IcmpAliasOut2(la, pip);
642 case ICMP_TSTAMPREPLY:
643 iresult = IcmpAliasOut1(la, pip, create);
651 ProtoAliasIn(struct libalias *la, struct ip *pip)
654 Handle incoming IP packets. The
655 only thing which is done in this case is to alias
656 the dest IP address of the packet to our inside
659 struct alias_link *lnk;
661 LIBALIAS_LOCK_ASSERT(la);
662 /* Return if proxy-only mode is enabled */
663 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
664 return (PKT_ALIAS_OK);
666 lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
668 struct in_addr original_address;
670 original_address = GetOriginalAddress(lnk);
672 /* Restore original IP address */
673 DifferentialChecksum(&pip->ip_sum,
674 &original_address, &pip->ip_dst, 2);
675 pip->ip_dst = original_address;
677 return (PKT_ALIAS_OK);
679 return (PKT_ALIAS_IGNORED);
684 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
687 Handle outgoing IP packets. The
688 only thing which is done in this case is to alias
689 the source IP address of the packet.
691 struct alias_link *lnk;
693 LIBALIAS_LOCK_ASSERT(la);
696 /* Return if proxy-only mode is enabled */
697 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
698 return (PKT_ALIAS_OK);
700 lnk = FindProtoOut(la, pip->ip_src, pip->ip_dst, pip->ip_p);
702 struct in_addr alias_address;
704 alias_address = GetAliasAddress(lnk);
706 /* Change source address */
707 DifferentialChecksum(&pip->ip_sum,
708 &alias_address, &pip->ip_src, 2);
709 pip->ip_src = alias_address;
711 return (PKT_ALIAS_OK);
713 return (PKT_ALIAS_IGNORED);
718 UdpAliasIn(struct libalias *la, struct ip *pip)
721 struct alias_link *lnk;
723 LIBALIAS_LOCK_ASSERT(la);
724 /* Return if proxy-only mode is enabled */
725 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
726 return (PKT_ALIAS_OK);
728 ud = (struct udphdr *)ip_next(pip);
730 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
731 ud->uh_sport, ud->uh_dport,
734 struct in_addr alias_address;
735 struct in_addr original_address;
739 struct alias_data ad = {
741 .oaddr = &original_address,
742 .aaddr = &alias_address,
743 .aport = &alias_port,
744 .sport = &ud->uh_sport,
745 .dport = &ud->uh_dport,
749 alias_address = GetAliasAddress(lnk);
750 original_address = GetOriginalAddress(lnk);
751 alias_port = ud->uh_dport;
752 ud->uh_dport = GetOriginalPort(lnk);
754 /* Walk out chain. */
755 error = find_handler(IN, UDP, la, pip, &ad);
757 /* If UDP checksum is not zero, then adjust since destination port */
758 /* is being unaliased and destination address is being altered. */
759 if (ud->uh_sum != 0) {
760 accumulate = alias_port;
761 accumulate -= ud->uh_dport;
762 accumulate += twowords(&alias_address);
763 accumulate -= twowords(&original_address);
764 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
766 /* Restore original IP address */
767 DifferentialChecksum(&pip->ip_sum,
768 &original_address, &pip->ip_dst, 2);
769 pip->ip_dst = original_address;
772 * If we cannot figure out the packet, ignore it.
775 return (PKT_ALIAS_IGNORED);
777 return (PKT_ALIAS_OK);
779 return (PKT_ALIAS_IGNORED);
783 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
786 struct alias_link *lnk;
789 LIBALIAS_LOCK_ASSERT(la);
790 /* Return if proxy-only mode is enabled */
791 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
792 return (PKT_ALIAS_OK);
794 ud = (struct udphdr *)ip_next(pip);
796 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
797 ud->uh_sport, ud->uh_dport,
798 IPPROTO_UDP, create);
801 struct in_addr alias_address;
802 struct alias_data ad = {
805 .aaddr = &alias_address,
806 .aport = &alias_port,
807 .sport = &ud->uh_sport,
808 .dport = &ud->uh_dport,
812 alias_address = GetAliasAddress(lnk);
813 alias_port = GetAliasPort(lnk);
815 /* Walk out chain. */
816 error = find_handler(OUT, UDP, la, pip, &ad);
818 /* If UDP checksum is not zero, adjust since source port is */
819 /* being aliased and source address is being altered */
820 if (ud->uh_sum != 0) {
823 accumulate = ud->uh_sport;
824 accumulate -= alias_port;
825 accumulate += twowords(&pip->ip_src);
826 accumulate -= twowords(&alias_address);
827 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
829 /* Put alias port in UDP header */
830 ud->uh_sport = alias_port;
832 /* Change source address */
833 DifferentialChecksum(&pip->ip_sum,
834 &alias_address, &pip->ip_src, 2);
835 pip->ip_src = alias_address;
837 return (PKT_ALIAS_OK);
839 return (PKT_ALIAS_IGNORED);
845 TcpAliasIn(struct libalias *la, struct ip *pip)
848 struct alias_link *lnk;
850 LIBALIAS_LOCK_ASSERT(la);
851 tc = (struct tcphdr *)ip_next(pip);
853 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
854 tc->th_sport, tc->th_dport,
856 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
858 struct in_addr alias_address;
859 struct in_addr original_address;
860 struct in_addr proxy_address;
863 int accumulate, error;
866 * The init of MANY vars is a bit below, but aliashandlepptpin
867 * seems to need the destination port that came within the
868 * packet and not the original one looks below [*].
871 struct alias_data ad = {
876 .sport = &tc->th_sport,
877 .dport = &tc->th_dport,
881 /* Walk out chain. */
882 error = find_handler(IN, TCP, la, pip, &ad);
884 alias_address = GetAliasAddress(lnk);
885 original_address = GetOriginalAddress(lnk);
886 proxy_address = GetProxyAddress(lnk);
887 alias_port = tc->th_dport;
888 tc->th_dport = GetOriginalPort(lnk);
889 proxy_port = GetProxyPort(lnk);
892 * Look above, if anyone is going to add find_handler AFTER
893 * this aliashandlepptpin/point, please redo alias_data too.
894 * Uncommenting the piece here below should be enough.
897 struct alias_data ad = {
899 .oaddr = &original_address,
900 .aaddr = &alias_address,
901 .aport = &alias_port,
902 .sport = &ud->uh_sport,
903 .dport = &ud->uh_dport,
907 /* Walk out chain. */
908 error = find_handler(la, pip, &ad);
910 printf("Protocol handler not found\n");
913 /* Adjust TCP checksum since destination port is being unaliased */
914 /* and destination port is being altered. */
915 accumulate = alias_port;
916 accumulate -= tc->th_dport;
917 accumulate += twowords(&alias_address);
918 accumulate -= twowords(&original_address);
920 /* If this is a proxy, then modify the TCP source port and
921 checksum accumulation */
922 if (proxy_port != 0) {
923 accumulate += tc->th_sport;
924 tc->th_sport = proxy_port;
925 accumulate -= tc->th_sport;
926 accumulate += twowords(&pip->ip_src);
927 accumulate -= twowords(&proxy_address);
929 /* See if ACK number needs to be modified */
930 if (GetAckModified(lnk) == 1) {
933 delta = GetDeltaAckIn(pip, lnk);
935 accumulate += twowords(&tc->th_ack);
936 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
937 accumulate -= twowords(&tc->th_ack);
940 ADJUST_CHECKSUM(accumulate, tc->th_sum);
942 /* Restore original IP address */
943 accumulate = twowords(&pip->ip_dst);
944 pip->ip_dst = original_address;
945 accumulate -= twowords(&pip->ip_dst);
947 /* If this is a transparent proxy packet, then modify the source
949 if (proxy_address.s_addr != 0) {
950 accumulate += twowords(&pip->ip_src);
951 pip->ip_src = proxy_address;
952 accumulate -= twowords(&pip->ip_src);
954 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
956 /* Monitor TCP connection state */
957 TcpMonitorIn(pip, lnk);
959 return (PKT_ALIAS_OK);
961 return (PKT_ALIAS_IGNORED);
965 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
967 int proxy_type, error;
969 u_short proxy_server_port;
970 struct in_addr dest_address;
971 struct in_addr proxy_server_address;
973 struct alias_link *lnk;
975 LIBALIAS_LOCK_ASSERT(la);
976 tc = (struct tcphdr *)ip_next(pip);
980 ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
984 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
985 return (PKT_ALIAS_OK);
987 /* If this is a transparent proxy, save original destination,
988 then alter the destination and adjust checksums */
989 dest_port = tc->th_dport;
990 dest_address = pip->ip_dst;
991 if (proxy_type != 0) {
994 accumulate = tc->th_dport;
995 tc->th_dport = proxy_server_port;
996 accumulate -= tc->th_dport;
997 accumulate += twowords(&pip->ip_dst);
998 accumulate -= twowords(&proxy_server_address);
999 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1001 accumulate = twowords(&pip->ip_dst);
1002 pip->ip_dst = proxy_server_address;
1003 accumulate -= twowords(&pip->ip_dst);
1004 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1006 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1007 tc->th_sport, tc->th_dport,
1008 IPPROTO_TCP, create);
1010 return (PKT_ALIAS_IGNORED);
1013 struct in_addr alias_address;
1015 struct alias_data ad = {
1018 .aaddr = &alias_address,
1019 .aport = &alias_port,
1020 .sport = &tc->th_sport,
1021 .dport = &tc->th_dport,
1022 .maxpktsize = maxpacketsize
1025 /* Save original destination address, if this is a proxy packet.
1026 Also modify packet to include destination encoding. This may
1027 change the size of IP header. */
1028 if (proxy_type != 0) {
1029 SetProxyPort(lnk, dest_port);
1030 SetProxyAddress(lnk, dest_address);
1031 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1032 tc = (struct tcphdr *)ip_next(pip);
1034 /* Get alias address and port */
1035 alias_port = GetAliasPort(lnk);
1036 alias_address = GetAliasAddress(lnk);
1038 /* Monitor TCP connection state */
1039 TcpMonitorOut(pip, lnk);
1041 /* Walk out chain. */
1042 error = find_handler(OUT, TCP, la, pip, &ad);
1044 /* Adjust TCP checksum since source port is being aliased */
1045 /* and source address is being altered */
1046 accumulate = tc->th_sport;
1047 tc->th_sport = alias_port;
1048 accumulate -= tc->th_sport;
1049 accumulate += twowords(&pip->ip_src);
1050 accumulate -= twowords(&alias_address);
1052 /* Modify sequence number if necessary */
1053 if (GetAckModified(lnk) == 1) {
1056 delta = GetDeltaSeqOut(pip, lnk);
1058 accumulate += twowords(&tc->th_seq);
1059 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1060 accumulate -= twowords(&tc->th_seq);
1063 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1065 /* Change source address */
1066 accumulate = twowords(&pip->ip_src);
1067 pip->ip_src = alias_address;
1068 accumulate -= twowords(&pip->ip_src);
1069 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1071 return (PKT_ALIAS_OK);
1073 return (PKT_ALIAS_IGNORED);
1079 /* Fragment Handling
1084 The packet aliasing module has a limited ability for handling IP
1085 fragments. If the ICMP, TCP or UDP header is in the first fragment
1086 received, then the ID number of the IP packet is saved, and other
1087 fragments are identified according to their ID number and IP address
1088 they were sent from. Pointers to unresolved fragments can also be
1089 saved and recalled when a header fragment is seen.
1092 /* Local prototypes */
1093 static int FragmentIn(struct libalias *, struct ip *);
1094 static int FragmentOut(struct libalias *, struct ip *);
1098 FragmentIn(struct libalias *la, struct ip *pip)
1100 struct alias_link *lnk;
1102 LIBALIAS_LOCK_ASSERT(la);
1103 lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1105 struct in_addr original_address;
1107 GetFragmentAddr(lnk, &original_address);
1108 DifferentialChecksum(&pip->ip_sum,
1109 &original_address, &pip->ip_dst, 2);
1110 pip->ip_dst = original_address;
1112 return (PKT_ALIAS_OK);
1114 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1119 FragmentOut(struct libalias *la, struct ip *pip)
1121 struct in_addr alias_address;
1123 LIBALIAS_LOCK_ASSERT(la);
1124 alias_address = FindAliasAddress(la, pip->ip_src);
1125 DifferentialChecksum(&pip->ip_sum,
1126 &alias_address, &pip->ip_src, 2);
1127 pip->ip_src = alias_address;
1129 return (PKT_ALIAS_OK);
1137 /* Outside World Access
1139 PacketAliasSaveFragment()
1140 PacketAliasGetFragment()
1141 PacketAliasFragmentIn()
1146 (prototypes in alias.h)
1151 LibAliasSaveFragment(struct libalias *la, char *ptr)
1154 struct alias_link *lnk;
1158 pip = (struct ip *)ptr;
1159 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1160 iresult = PKT_ALIAS_ERROR;
1162 SetFragmentPtr(lnk, ptr);
1163 iresult = PKT_ALIAS_OK;
1165 LIBALIAS_UNLOCK(la);
1171 LibAliasGetFragment(struct libalias *la, char *ptr)
1173 struct alias_link *lnk;
1178 pip = (struct ip *)ptr;
1179 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1181 GetFragmentPtr(lnk, &fptr);
1182 SetFragmentPtr(lnk, NULL);
1183 SetExpire(lnk, 0); /* Deletes link */
1187 LIBALIAS_UNLOCK(la);
1193 LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly
1196 char *ptr_fragment /* Points to fragment which must be
1205 pip = (struct ip *)ptr;
1206 fpip = (struct ip *)ptr_fragment;
1208 DifferentialChecksum(&fpip->ip_sum,
1209 &pip->ip_dst, &fpip->ip_dst, 2);
1210 fpip->ip_dst = pip->ip_dst;
1211 LIBALIAS_UNLOCK(la);
1214 /* Local prototypes */
1216 LibAliasOutLocked(struct libalias *la, char *ptr,
1217 int maxpacketsize, int create);
1219 LibAliasInLocked(struct libalias *la, char *ptr,
1223 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1228 res = LibAliasInLocked(la, ptr, maxpacketsize);
1229 LIBALIAS_UNLOCK(la);
1234 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1236 struct in_addr alias_addr;
1240 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1241 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1242 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1243 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1247 ClearCheckNewLink(la);
1248 pip = (struct ip *)ptr;
1249 alias_addr = pip->ip_dst;
1251 /* Defense against mangled packets */
1252 if (ntohs(pip->ip_len) > maxpacketsize
1253 || (pip->ip_hl << 2) > maxpacketsize) {
1254 iresult = PKT_ALIAS_IGNORED;
1258 iresult = PKT_ALIAS_IGNORED;
1259 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1260 switch (pip->ip_p) {
1262 iresult = IcmpAliasIn(la, pip);
1265 iresult = UdpAliasIn(la, pip);
1268 iresult = TcpAliasIn(la, pip);
1272 struct alias_data ad = {
1282 /* Walk out chain. */
1283 error = find_handler(IN, IP, la, pip, &ad);
1285 iresult = PKT_ALIAS_OK;
1287 iresult = ProtoAliasIn(la, pip);
1291 iresult = ProtoAliasIn(la, pip);
1295 if (ntohs(pip->ip_off) & IP_MF) {
1296 struct alias_link *lnk;
1298 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1300 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1301 SetFragmentAddr(lnk, pip->ip_dst);
1303 iresult = PKT_ALIAS_ERROR;
1307 iresult = FragmentIn(la, pip);
1316 /* Unregistered address ranges */
1318 /* 10.0.0.0 -> 10.255.255.255 */
1319 #define UNREG_ADDR_A_LOWER 0x0a000000
1320 #define UNREG_ADDR_A_UPPER 0x0affffff
1322 /* 172.16.0.0 -> 172.31.255.255 */
1323 #define UNREG_ADDR_B_LOWER 0xac100000
1324 #define UNREG_ADDR_B_UPPER 0xac1fffff
1326 /* 192.168.0.0 -> 192.168.255.255 */
1327 #define UNREG_ADDR_C_LOWER 0xc0a80000
1328 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1331 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1336 res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1337 LIBALIAS_UNLOCK(la);
1342 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1347 res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1348 LIBALIAS_UNLOCK(la);
1353 LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */
1354 int maxpacketsize, /* How much the packet data may grow (FTP
1355 * and IRC inline changes) */
1356 int create /* Create new entries ? */
1360 struct in_addr addr_save;
1363 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1364 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1365 iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1366 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1370 ClearCheckNewLink(la);
1371 pip = (struct ip *)ptr;
1373 /* Defense against mangled packets */
1374 if (ntohs(pip->ip_len) > maxpacketsize
1375 || (pip->ip_hl << 2) > maxpacketsize) {
1376 iresult = PKT_ALIAS_IGNORED;
1380 addr_save = GetDefaultAliasAddress(la);
1381 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1386 addr = ntohl(pip->ip_src.s_addr);
1387 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1389 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1391 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1395 SetDefaultAliasAddress(la, pip->ip_src);
1397 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1398 SetDefaultAliasAddress(la, pip->ip_src);
1400 iresult = PKT_ALIAS_IGNORED;
1401 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1402 switch (pip->ip_p) {
1404 iresult = IcmpAliasOut(la, pip, create);
1407 iresult = UdpAliasOut(la, pip, create);
1410 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1414 struct alias_data ad = {
1423 /* Walk out chain. */
1424 error = find_handler(OUT, IP, la, pip, &ad);
1426 iresult = PKT_ALIAS_OK;
1428 iresult = ProtoAliasOut(la, pip, create);
1432 iresult = ProtoAliasOut(la, pip, create);
1436 iresult = FragmentOut(la, pip);
1439 SetDefaultAliasAddress(la, addr_save);
1445 LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1446 int maxpacketsize /* for error checking */
1453 struct alias_link *lnk;
1454 int iresult = PKT_ALIAS_IGNORED;
1457 pip = (struct ip *)ptr;
1459 /* Defense against mangled packets */
1460 if (ntohs(pip->ip_len) > maxpacketsize
1461 || (pip->ip_hl << 2) > maxpacketsize)
1464 ud = (struct udphdr *)ip_next(pip);
1465 tc = (struct tcphdr *)ip_next(pip);
1466 ic = (struct icmp *)ip_next(pip);
1469 if (pip->ip_p == IPPROTO_UDP)
1470 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1471 ud->uh_dport, ud->uh_sport,
1473 else if (pip->ip_p == IPPROTO_TCP)
1474 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1475 tc->th_dport, tc->th_sport,
1477 else if (pip->ip_p == IPPROTO_ICMP)
1478 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1482 /* Change it from an aliased packet to an unaliased packet */
1484 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1486 struct in_addr original_address;
1487 u_short original_port;
1489 original_address = GetOriginalAddress(lnk);
1490 original_port = GetOriginalPort(lnk);
1492 /* Adjust TCP/UDP checksum */
1493 accumulate = twowords(&pip->ip_src);
1494 accumulate -= twowords(&original_address);
1496 if (pip->ip_p == IPPROTO_UDP) {
1497 accumulate += ud->uh_sport;
1498 accumulate -= original_port;
1499 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1501 accumulate += tc->th_sport;
1502 accumulate -= original_port;
1503 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1506 /* Adjust IP checksum */
1507 DifferentialChecksum(&pip->ip_sum,
1508 &original_address, &pip->ip_src, 2);
1510 /* Un-alias source address and port number */
1511 pip->ip_src = original_address;
1512 if (pip->ip_p == IPPROTO_UDP)
1513 ud->uh_sport = original_port;
1515 tc->th_sport = original_port;
1517 iresult = PKT_ALIAS_OK;
1519 } else if (pip->ip_p == IPPROTO_ICMP) {
1522 struct in_addr original_address;
1523 u_short original_id;
1525 original_address = GetOriginalAddress(lnk);
1526 original_id = GetOriginalPort(lnk);
1528 /* Adjust ICMP checksum */
1529 accumulate = twowords(&pip->ip_src);
1530 accumulate -= twowords(&original_address);
1531 accumulate += ic->icmp_id;
1532 accumulate -= original_id;
1533 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1535 /* Adjust IP checksum */
1536 DifferentialChecksum(&pip->ip_sum,
1537 &original_address, &pip->ip_src, 2);
1539 /* Un-alias source address and port number */
1540 pip->ip_src = original_address;
1541 ic->icmp_id = original_id;
1543 iresult = PKT_ALIAS_OK;
1547 LIBALIAS_UNLOCK(la);
1555 LibAliasRefreshModules(void)
1557 char buf[256], conf[] = "/etc/libalias.conf";
1561 fd = fopen(conf, "r");
1563 err(1, "fopen(%s)", conf);
1565 LibAliasUnLoadAllModule();
1568 fgets(buf, 256, fd);
1573 for (i = 0; i < len; i++)
1574 if (!isspace(buf[i]))
1578 buf[len - 1] = '\0';
1579 printf("Loading %s\n", buf);
1580 LibAliasLoadModule(buf);
1587 LibAliasLoadModule(char *path)
1591 struct proto_handler *m;
1595 handle = dlopen (path, RTLD_LAZY);
1597 fprintf(stderr, "%s\n", dlerror());
1601 p = dlsym(handle, "alias_mod");
1602 if ((error = dlerror()) != NULL) {
1603 fprintf(stderr, "%s\n", dlerror());
1607 t = malloc(sizeof(struct dll));
1610 strncpy(t->name, p->name, DLL_LEN);
1612 if (attach_dll(t) == EEXIST) {
1614 fprintf(stderr, "dll conflict\n");
1618 m = dlsym(t->handle, "handlers");
1619 if ((error = dlerror()) != NULL) {
1620 fprintf(stderr, "%s\n", error);
1624 LibAliasAttachHandlers(m);
1629 LibAliasUnLoadAllModule(void)
1632 struct proto_handler *p;
1634 /* Unload all modules then reload everything. */
1635 while ((p = first_handler()) != NULL) {
1638 while ((t = walk_dll_chain()) != NULL) {
1649 * m_megapullup() - this function is a big hack.
1650 * Thankfully, it's only used in ng_nat and ipfw+nat.
1652 * It allocates an mbuf with cluster and copies the specified part of the chain
1653 * into cluster, so that it is all contiguous and can be accessed via a plain
1654 * (char *) pointer. This is required, because libalias doesn't know how to
1655 * handle mbuf chains.
1657 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1658 * the input packet, on failure NULL. The input packet is always consumed.
1661 m_megapullup(struct mbuf *m, int len) {
1664 if (len > m->m_pkthdr.len)
1667 /* Do not reallocate packet if it is sequentional,
1668 * writable and has some extra space for expansion.
1669 * XXX: Constant 100bytes is completely empirical. */
1671 if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE)
1674 if (len <= MCLBYTES - RESERVE) {
1675 mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1676 } else if (len < MJUM16BYTES) {
1678 if (len <= MJUMPAGESIZE - RESERVE) {
1679 size = MJUMPAGESIZE;
1680 } else if (len <= MJUM9BYTES - RESERVE) {
1685 mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1692 m_move_pkthdr(mcl, m);
1693 m_copydata(m, 0, len, mtod(mcl, caddr_t));
1694 mcl->m_len = mcl->m_pkthdr.len = len;