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/param.h>
115 #include <sys/systm.h>
116 #include <sys/mbuf.h>
118 #include <netinet/in_systm.h>
119 #include <netinet/in.h>
120 #include <netinet/ip.h>
121 #include <netinet/ip_icmp.h>
122 #include <netinet/tcp.h>
123 #include <netinet/udp.h>
126 #include "alias_local.h"
127 #include "alias_mod.h"
134 #if BYTE_ORDER == LITTLE_ENDIAN
135 uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
136 uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
138 uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
139 uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
144 /* TCP Handling Routines
146 TcpMonitorIn() -- These routines monitor TCP connections, and
147 TcpMonitorOut() delete a link when a connection is closed.
149 These routines look for SYN, FIN and RST flags to determine when TCP
150 connections open and close. When a TCP connection closes, the data
151 structure containing packet aliasing information is deleted after
155 /* Local prototypes */
156 static void TcpMonitorIn(struct ip *, struct alias_link *);
158 static void TcpMonitorOut(struct ip *, struct alias_link *);
162 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
166 tc = (struct tcphdr *)ip_next(pip);
168 switch (GetStateIn(lnk)) {
169 case ALIAS_TCP_STATE_NOT_CONNECTED:
170 if (tc->th_flags & TH_RST)
171 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
172 else if (tc->th_flags & TH_SYN)
173 SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
175 case ALIAS_TCP_STATE_CONNECTED:
176 if (tc->th_flags & (TH_FIN | TH_RST))
177 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
183 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
187 tc = (struct tcphdr *)ip_next(pip);
189 switch (GetStateOut(lnk)) {
190 case ALIAS_TCP_STATE_NOT_CONNECTED:
191 if (tc->th_flags & TH_RST)
192 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
193 else if (tc->th_flags & TH_SYN)
194 SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
196 case ALIAS_TCP_STATE_CONNECTED:
197 if (tc->th_flags & (TH_FIN | TH_RST))
198 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
207 /* Protocol Specific Packet Aliasing Routines
209 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
210 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
211 ProtoAliasIn(), ProtoAliasOut()
212 UdpAliasIn(), UdpAliasOut()
213 TcpAliasIn(), TcpAliasOut()
215 These routines handle protocol specific details of packet aliasing.
216 One may observe a certain amount of repetitive arithmetic in these
217 functions, the purpose of which is to compute a revised checksum
218 without actually summing over the entire data packet, which could be
219 unnecessarily time consuming.
221 The purpose of the packet aliasing routines is to replace the source
222 address of the outgoing packet and then correctly put it back for
223 any incoming packets. For TCP and UDP, ports are also re-mapped.
225 For ICMP echo/timestamp requests and replies, the following scheme
226 is used: the ID number is replaced by an alias for the outgoing
229 ICMP error messages are handled by looking at the IP fragment
230 in the data section of the message.
232 For TCP and UDP protocols, a port number is chosen for an outgoing
233 packet, and then incoming packets are identified by IP address and
234 port numbers. For TCP packets, there is additional logic in the event
235 that sequence and ACK numbers have been altered (as in the case for
236 FTP data port commands).
238 The port numbers used by the packet aliasing module are not true
239 ports in the Unix sense. No sockets are actually bound to ports.
240 They are more correctly thought of as placeholders.
242 All packets go through the aliasing mechanism, whether they come from
243 the gateway machine or other machines on a local area network.
247 /* Local prototypes */
248 static int IcmpAliasIn1(struct libalias *, struct ip *);
249 static int IcmpAliasIn2(struct libalias *, struct ip *);
250 static int IcmpAliasIn(struct libalias *, struct ip *);
252 static int IcmpAliasOut1(struct libalias *, struct ip *, int create);
253 static int IcmpAliasOut2(struct libalias *, struct ip *);
254 static int IcmpAliasOut(struct libalias *, struct ip *, int create);
256 static int ProtoAliasIn(struct libalias *, struct ip *);
257 static int ProtoAliasOut(struct libalias *, struct ip *, int create);
259 static int UdpAliasIn(struct libalias *, struct ip *);
260 static int UdpAliasOut(struct libalias *, struct ip *, int create);
262 static int TcpAliasIn(struct libalias *, struct ip *);
263 static int TcpAliasOut(struct libalias *, struct ip *, int, int create);
267 IcmpAliasIn1(struct libalias *la, struct ip *pip)
270 LIBALIAS_LOCK_ASSERT(la);
272 De-alias incoming echo and timestamp replies.
273 Alias incoming echo and timestamp requests.
275 struct alias_link *lnk;
278 ic = (struct icmp *)ip_next(pip);
280 /* Get source address from ICMP data field and restore original data */
281 lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
286 original_id = GetOriginalPort(lnk);
288 /* Adjust ICMP checksum */
289 accumulate = ic->icmp_id;
290 accumulate -= original_id;
291 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
293 /* Put original sequence number back in */
294 ic->icmp_id = original_id;
296 /* Put original address back into IP header */
298 struct in_addr original_address;
300 original_address = GetOriginalAddress(lnk);
301 DifferentialChecksum(&pip->ip_sum,
302 &original_address, &pip->ip_dst, 2);
303 pip->ip_dst = original_address;
306 return (PKT_ALIAS_OK);
308 return (PKT_ALIAS_IGNORED);
312 IcmpAliasIn2(struct libalias *la, struct ip *pip)
315 LIBALIAS_LOCK_ASSERT(la);
317 Alias incoming ICMP error messages containing
318 IP header and first 64 bits of datagram.
321 struct icmp *ic, *ic2;
324 struct alias_link *lnk;
326 ic = (struct icmp *)ip_next(pip);
329 ud = (struct udphdr *)ip_next(ip);
330 tc = (struct tcphdr *)ip_next(ip);
331 ic2 = (struct icmp *)ip_next(ip);
333 if (ip->ip_p == IPPROTO_UDP)
334 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
335 ud->uh_dport, ud->uh_sport,
337 else if (ip->ip_p == IPPROTO_TCP)
338 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
339 tc->th_dport, tc->th_sport,
341 else if (ip->ip_p == IPPROTO_ICMP) {
342 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
343 lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
350 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
351 int accumulate, accumulate2;
352 struct in_addr original_address;
353 u_short original_port;
355 original_address = GetOriginalAddress(lnk);
356 original_port = GetOriginalPort(lnk);
358 /* Adjust ICMP checksum */
359 accumulate = twowords(&ip->ip_src);
360 accumulate -= twowords(&original_address);
361 accumulate += ud->uh_sport;
362 accumulate -= original_port;
363 accumulate2 = accumulate;
364 accumulate2 += ip->ip_sum;
365 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
366 accumulate2 -= ip->ip_sum;
367 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
369 /* Un-alias address in IP header */
370 DifferentialChecksum(&pip->ip_sum,
371 &original_address, &pip->ip_dst, 2);
372 pip->ip_dst = original_address;
374 /* Un-alias address and port number of original IP packet
375 fragment contained in ICMP data section */
376 ip->ip_src = original_address;
377 ud->uh_sport = original_port;
378 } else if (ip->ip_p == IPPROTO_ICMP) {
379 int accumulate, accumulate2;
380 struct in_addr original_address;
383 original_address = GetOriginalAddress(lnk);
384 original_id = GetOriginalPort(lnk);
386 /* Adjust ICMP checksum */
387 accumulate = twowords(&ip->ip_src);
388 accumulate -= twowords(&original_address);
389 accumulate += ic2->icmp_id;
390 accumulate -= original_id;
391 accumulate2 = accumulate;
392 accumulate2 += ip->ip_sum;
393 ADJUST_CHECKSUM(accumulate, ip->ip_sum);
394 accumulate2 -= ip->ip_sum;
395 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
397 /* Un-alias address in IP header */
398 DifferentialChecksum(&pip->ip_sum,
399 &original_address, &pip->ip_dst, 2);
400 pip->ip_dst = original_address;
402 /* Un-alias address of original IP packet and sequence number of
403 embedded ICMP datagram */
404 ip->ip_src = original_address;
405 ic2->icmp_id = original_id;
407 return (PKT_ALIAS_OK);
409 return (PKT_ALIAS_IGNORED);
414 IcmpAliasIn(struct libalias *la, struct ip *pip)
419 LIBALIAS_LOCK_ASSERT(la);
420 /* Return if proxy-only mode is enabled */
421 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
422 return (PKT_ALIAS_OK);
424 ic = (struct icmp *)ip_next(pip);
426 iresult = PKT_ALIAS_IGNORED;
427 switch (ic->icmp_type) {
429 case ICMP_TSTAMPREPLY:
430 if (ic->icmp_code == 0) {
431 iresult = IcmpAliasIn1(la, pip);
435 case ICMP_SOURCEQUENCH:
438 iresult = IcmpAliasIn2(la, pip);
442 iresult = IcmpAliasIn1(la, pip);
450 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
453 Alias outgoing echo and timestamp requests.
454 De-alias outgoing echo and timestamp replies.
456 struct alias_link *lnk;
459 LIBALIAS_LOCK_ASSERT(la);
460 ic = (struct icmp *)ip_next(pip);
462 /* Save overwritten data for when echo packet returns */
463 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
468 alias_id = GetAliasPort(lnk);
470 /* Since data field is being modified, adjust ICMP checksum */
471 accumulate = ic->icmp_id;
472 accumulate -= alias_id;
473 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
475 /* Alias sequence number */
476 ic->icmp_id = alias_id;
478 /* Change source address */
480 struct in_addr alias_address;
482 alias_address = GetAliasAddress(lnk);
483 DifferentialChecksum(&pip->ip_sum,
484 &alias_address, &pip->ip_src, 2);
485 pip->ip_src = alias_address;
488 return (PKT_ALIAS_OK);
490 return (PKT_ALIAS_IGNORED);
495 IcmpAliasOut2(struct libalias *la, struct ip *pip)
498 Alias outgoing ICMP error messages containing
499 IP header and first 64 bits of datagram.
502 struct icmp *ic, *ic2;
505 struct alias_link *lnk;
507 LIBALIAS_LOCK_ASSERT(la);
508 ic = (struct icmp *)ip_next(pip);
511 ud = (struct udphdr *)ip_next(ip);
512 tc = (struct tcphdr *)ip_next(ip);
513 ic2 = (struct icmp *)ip_next(ip);
515 if (ip->ip_p == IPPROTO_UDP)
516 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
517 ud->uh_dport, ud->uh_sport,
519 else if (ip->ip_p == IPPROTO_TCP)
520 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
521 tc->th_dport, tc->th_sport,
523 else if (ip->ip_p == IPPROTO_ICMP) {
524 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
525 lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
532 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
534 struct in_addr alias_address;
537 alias_address = GetAliasAddress(lnk);
538 alias_port = GetAliasPort(lnk);
540 /* Adjust ICMP checksum */
541 accumulate = twowords(&ip->ip_dst);
542 accumulate -= twowords(&alias_address);
543 accumulate += ud->uh_dport;
544 accumulate -= alias_port;
545 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
548 * Alias address in IP header if it comes from the host
549 * the original TCP/UDP packet was destined for.
551 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
552 DifferentialChecksum(&pip->ip_sum,
553 &alias_address, &pip->ip_src, 2);
554 pip->ip_src = alias_address;
556 /* Alias address and port number of original IP packet
557 fragment contained in ICMP data section */
558 ip->ip_dst = alias_address;
559 ud->uh_dport = alias_port;
560 } else if (ip->ip_p == IPPROTO_ICMP) {
562 struct in_addr alias_address;
565 alias_address = GetAliasAddress(lnk);
566 alias_id = GetAliasPort(lnk);
568 /* Adjust ICMP checksum */
569 accumulate = twowords(&ip->ip_dst);
570 accumulate -= twowords(&alias_address);
571 accumulate += ic2->icmp_id;
572 accumulate -= alias_id;
573 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
576 * Alias address in IP header if it comes from the host
577 * the original ICMP message was destined for.
579 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
580 DifferentialChecksum(&pip->ip_sum,
581 &alias_address, &pip->ip_src, 2);
582 pip->ip_src = alias_address;
584 /* Alias address of original IP packet and sequence number of
585 embedded ICMP datagram */
586 ip->ip_dst = alias_address;
587 ic2->icmp_id = alias_id;
589 return (PKT_ALIAS_OK);
591 return (PKT_ALIAS_IGNORED);
596 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
601 LIBALIAS_LOCK_ASSERT(la);
604 /* Return if proxy-only mode is enabled */
605 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
606 return (PKT_ALIAS_OK);
608 ic = (struct icmp *)ip_next(pip);
610 iresult = PKT_ALIAS_IGNORED;
611 switch (ic->icmp_type) {
614 if (ic->icmp_code == 0) {
615 iresult = IcmpAliasOut1(la, pip, create);
619 case ICMP_SOURCEQUENCH:
622 iresult = IcmpAliasOut2(la, pip);
625 case ICMP_TSTAMPREPLY:
626 iresult = IcmpAliasOut1(la, pip, create);
634 ProtoAliasIn(struct libalias *la, struct ip *pip)
637 Handle incoming IP packets. The
638 only thing which is done in this case is to alias
639 the dest IP address of the packet to our inside
642 struct alias_link *lnk;
644 LIBALIAS_LOCK_ASSERT(la);
645 /* Return if proxy-only mode is enabled */
646 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
647 return (PKT_ALIAS_OK);
649 lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
651 struct in_addr original_address;
653 original_address = GetOriginalAddress(lnk);
655 /* Restore original IP address */
656 DifferentialChecksum(&pip->ip_sum,
657 &original_address, &pip->ip_dst, 2);
658 pip->ip_dst = original_address;
660 return (PKT_ALIAS_OK);
662 return (PKT_ALIAS_IGNORED);
667 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
670 Handle outgoing IP packets. The
671 only thing which is done in this case is to alias
672 the source IP address of the packet.
674 struct alias_link *lnk;
676 LIBALIAS_LOCK_ASSERT(la);
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 LIBALIAS_LOCK_ASSERT(la);
707 /* Return if proxy-only mode is enabled */
708 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
709 return (PKT_ALIAS_OK);
711 ud = (struct udphdr *)ip_next(pip);
713 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
714 ud->uh_sport, ud->uh_dport,
717 struct in_addr alias_address;
718 struct in_addr original_address;
722 struct alias_data ad = {
724 .oaddr = &original_address,
725 .aaddr = &alias_address,
726 .aport = &alias_port,
727 .sport = &ud->uh_sport,
728 .dport = &ud->uh_dport,
732 alias_address = GetAliasAddress(lnk);
733 original_address = GetOriginalAddress(lnk);
734 alias_port = ud->uh_dport;
735 ud->uh_dport = GetOriginalPort(lnk);
737 /* Walk out chain. */
738 error = find_handler(IN, UDP, la, pip, &ad);
740 /* If UDP checksum is not zero, then adjust since destination port */
741 /* is being unaliased and destination address is being altered. */
742 if (ud->uh_sum != 0) {
743 accumulate = alias_port;
744 accumulate -= ud->uh_dport;
745 accumulate += twowords(&alias_address);
746 accumulate -= twowords(&original_address);
747 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
749 /* Restore original IP address */
750 DifferentialChecksum(&pip->ip_sum,
751 &original_address, &pip->ip_dst, 2);
752 pip->ip_dst = original_address;
755 * If we cannot figure out the packet, ignore it.
758 return (PKT_ALIAS_IGNORED);
760 return (PKT_ALIAS_OK);
762 return (PKT_ALIAS_IGNORED);
766 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
769 struct alias_link *lnk;
772 LIBALIAS_LOCK_ASSERT(la);
773 /* Return if proxy-only mode is enabled */
774 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
775 return (PKT_ALIAS_OK);
777 ud = (struct udphdr *)ip_next(pip);
779 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
780 ud->uh_sport, ud->uh_dport,
781 IPPROTO_UDP, create);
784 struct in_addr alias_address;
785 struct alias_data ad = {
788 .aaddr = &alias_address,
789 .aport = &alias_port,
790 .sport = &ud->uh_sport,
791 .dport = &ud->uh_dport,
795 alias_address = GetAliasAddress(lnk);
796 alias_port = GetAliasPort(lnk);
798 /* Walk out chain. */
799 error = find_handler(OUT, UDP, la, pip, &ad);
801 /* If UDP checksum is not zero, adjust since source port is */
802 /* being aliased and source address is being altered */
803 if (ud->uh_sum != 0) {
806 accumulate = ud->uh_sport;
807 accumulate -= alias_port;
808 accumulate += twowords(&pip->ip_src);
809 accumulate -= twowords(&alias_address);
810 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
812 /* Put alias port in UDP header */
813 ud->uh_sport = alias_port;
815 /* Change source address */
816 DifferentialChecksum(&pip->ip_sum,
817 &alias_address, &pip->ip_src, 2);
818 pip->ip_src = alias_address;
820 return (PKT_ALIAS_OK);
822 return (PKT_ALIAS_IGNORED);
828 TcpAliasIn(struct libalias *la, struct ip *pip)
831 struct alias_link *lnk;
833 LIBALIAS_LOCK_ASSERT(la);
834 tc = (struct tcphdr *)ip_next(pip);
836 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
837 tc->th_sport, tc->th_dport,
839 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
841 struct in_addr alias_address;
842 struct in_addr original_address;
843 struct in_addr proxy_address;
846 int accumulate, error;
849 * The init of MANY vars is a bit below, but aliashandlepptpin
850 * seems to need the destination port that came within the
851 * packet and not the original one looks below [*].
854 struct alias_data ad = {
859 .sport = &tc->th_sport,
860 .dport = &tc->th_dport,
864 /* Walk out chain. */
865 error = find_handler(IN, TCP, la, pip, &ad);
867 alias_address = GetAliasAddress(lnk);
868 original_address = GetOriginalAddress(lnk);
869 proxy_address = GetProxyAddress(lnk);
870 alias_port = tc->th_dport;
871 tc->th_dport = GetOriginalPort(lnk);
872 proxy_port = GetProxyPort(lnk);
875 * Look above, if anyone is going to add find_handler AFTER
876 * this aliashandlepptpin/point, please redo alias_data too.
877 * Uncommenting the piece here below should be enough.
880 struct alias_data ad = {
882 .oaddr = &original_address,
883 .aaddr = &alias_address,
884 .aport = &alias_port,
885 .sport = &ud->uh_sport,
886 .dport = &ud->uh_dport,
890 /* Walk out chain. */
891 error = find_handler(la, pip, &ad);
893 kprintf("Protocol handler not found\n");
896 /* Adjust TCP checksum since destination port is being unaliased */
897 /* and destination port is being altered. */
898 accumulate = alias_port;
899 accumulate -= tc->th_dport;
900 accumulate += twowords(&alias_address);
901 accumulate -= twowords(&original_address);
903 /* If this is a proxy, then modify the TCP source port and
904 checksum accumulation */
905 if (proxy_port != 0) {
906 accumulate += tc->th_sport;
907 tc->th_sport = proxy_port;
908 accumulate -= tc->th_sport;
909 accumulate += twowords(&pip->ip_src);
910 accumulate -= twowords(&proxy_address);
912 /* See if ACK number needs to be modified */
913 if (GetAckModified(lnk) == 1) {
916 delta = GetDeltaAckIn(pip, lnk);
918 accumulate += twowords(&tc->th_ack);
919 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
920 accumulate -= twowords(&tc->th_ack);
923 ADJUST_CHECKSUM(accumulate, tc->th_sum);
925 /* Restore original IP address */
926 accumulate = twowords(&pip->ip_dst);
927 pip->ip_dst = original_address;
928 accumulate -= twowords(&pip->ip_dst);
930 /* If this is a transparent proxy packet, then modify the source
932 if (proxy_address.s_addr != 0) {
933 accumulate += twowords(&pip->ip_src);
934 pip->ip_src = proxy_address;
935 accumulate -= twowords(&pip->ip_src);
937 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
939 /* Monitor TCP connection state */
940 TcpMonitorIn(pip, lnk);
942 return (PKT_ALIAS_OK);
944 return (PKT_ALIAS_IGNORED);
948 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
950 int proxy_type, error;
952 u_short proxy_server_port;
953 struct in_addr dest_address;
954 struct in_addr proxy_server_address;
956 struct alias_link *lnk;
958 LIBALIAS_LOCK_ASSERT(la);
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 LIBALIAS_LOCK_ASSERT(la);
1086 lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1088 struct in_addr original_address;
1090 GetFragmentAddr(lnk, &original_address);
1091 DifferentialChecksum(&pip->ip_sum,
1092 &original_address, &pip->ip_dst, 2);
1093 pip->ip_dst = original_address;
1095 return (PKT_ALIAS_OK);
1097 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1102 FragmentOut(struct libalias *la, struct ip *pip)
1104 struct in_addr alias_address;
1106 LIBALIAS_LOCK_ASSERT(la);
1107 alias_address = FindAliasAddress(la, pip->ip_src);
1108 DifferentialChecksum(&pip->ip_sum,
1109 &alias_address, &pip->ip_src, 2);
1110 pip->ip_src = alias_address;
1112 return (PKT_ALIAS_OK);
1120 /* Outside World Access
1122 PacketAliasSaveFragment()
1123 PacketAliasGetFragment()
1124 PacketAliasFragmentIn()
1129 (prototypes in alias.h)
1134 LibAliasSaveFragment(struct libalias *la, char *ptr)
1137 struct alias_link *lnk;
1141 pip = (struct ip *)ptr;
1142 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1143 iresult = PKT_ALIAS_ERROR;
1145 SetFragmentPtr(lnk, ptr);
1146 iresult = PKT_ALIAS_OK;
1148 LIBALIAS_UNLOCK(la);
1154 LibAliasGetFragment(struct libalias *la, char *ptr)
1156 struct alias_link *lnk;
1161 pip = (struct ip *)ptr;
1162 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1164 GetFragmentPtr(lnk, &fptr);
1165 SetFragmentPtr(lnk, NULL);
1166 SetExpire(lnk, 0); /* Deletes link */
1170 LIBALIAS_UNLOCK(la);
1176 LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly
1179 char *ptr_fragment /* Points to fragment which must be
1188 pip = (struct ip *)ptr;
1189 fpip = (struct ip *)ptr_fragment;
1191 DifferentialChecksum(&fpip->ip_sum,
1192 &pip->ip_dst, &fpip->ip_dst, 2);
1193 fpip->ip_dst = pip->ip_dst;
1194 LIBALIAS_UNLOCK(la);
1197 /* Local prototypes */
1199 LibAliasOutLocked(struct libalias *la, char *ptr,
1200 int maxpacketsize, int create);
1202 LibAliasInLocked(struct libalias *la, char *ptr,
1206 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1211 res = LibAliasInLocked(la, ptr, maxpacketsize);
1212 LIBALIAS_UNLOCK(la);
1217 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1219 struct in_addr alias_addr;
1223 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1224 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1225 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1226 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1230 ClearCheckNewLink(la);
1231 pip = (struct ip *)ptr;
1232 alias_addr = pip->ip_dst;
1234 /* Defense against mangled packets */
1235 if (ntohs(pip->ip_len) > maxpacketsize
1236 || (pip->ip_hl << 2) > maxpacketsize) {
1237 iresult = PKT_ALIAS_IGNORED;
1241 iresult = PKT_ALIAS_IGNORED;
1242 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1243 switch (pip->ip_p) {
1245 iresult = IcmpAliasIn(la, pip);
1248 iresult = UdpAliasIn(la, pip);
1251 iresult = TcpAliasIn(la, pip);
1255 struct alias_data ad = {
1265 /* Walk out chain. */
1266 error = find_handler(IN, IP, la, pip, &ad);
1268 iresult = PKT_ALIAS_OK;
1270 iresult = ProtoAliasIn(la, pip);
1274 iresult = ProtoAliasIn(la, pip);
1278 if (ntohs(pip->ip_off) & IP_MF) {
1279 struct alias_link *lnk;
1281 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1283 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1284 SetFragmentAddr(lnk, pip->ip_dst);
1286 iresult = PKT_ALIAS_ERROR;
1290 iresult = FragmentIn(la, pip);
1299 /* Unregistered address ranges */
1301 /* 10.0.0.0 -> 10.255.255.255 */
1302 #define UNREG_ADDR_A_LOWER 0x0a000000
1303 #define UNREG_ADDR_A_UPPER 0x0affffff
1305 /* 172.16.0.0 -> 172.31.255.255 */
1306 #define UNREG_ADDR_B_LOWER 0xac100000
1307 #define UNREG_ADDR_B_UPPER 0xac1fffff
1309 /* 192.168.0.0 -> 192.168.255.255 */
1310 #define UNREG_ADDR_C_LOWER 0xc0a80000
1311 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1314 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1319 res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1320 LIBALIAS_UNLOCK(la);
1325 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1330 res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1331 LIBALIAS_UNLOCK(la);
1336 LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */
1337 int maxpacketsize, /* How much the packet data may grow (FTP
1338 * and IRC inline changes) */
1339 int create /* Create new entries ? */
1343 struct in_addr addr_save;
1346 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1347 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1348 iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1349 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1353 ClearCheckNewLink(la);
1354 pip = (struct ip *)ptr;
1356 /* Defense against mangled packets */
1357 if (ntohs(pip->ip_len) > maxpacketsize
1358 || (pip->ip_hl << 2) > maxpacketsize) {
1359 iresult = PKT_ALIAS_IGNORED;
1363 addr_save = GetDefaultAliasAddress(la);
1364 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1369 addr = ntohl(pip->ip_src.s_addr);
1370 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1372 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1374 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1378 SetDefaultAliasAddress(la, pip->ip_src);
1380 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1381 SetDefaultAliasAddress(la, pip->ip_src);
1383 iresult = PKT_ALIAS_IGNORED;
1384 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1385 switch (pip->ip_p) {
1387 iresult = IcmpAliasOut(la, pip, create);
1390 iresult = UdpAliasOut(la, pip, create);
1393 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1397 struct alias_data ad = {
1406 /* Walk out chain. */
1407 error = find_handler(OUT, IP, la, pip, &ad);
1409 iresult = PKT_ALIAS_OK;
1411 iresult = ProtoAliasOut(la, pip, create);
1415 iresult = ProtoAliasOut(la, pip, create);
1419 iresult = FragmentOut(la, pip);
1422 SetDefaultAliasAddress(la, addr_save);
1428 LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1429 int maxpacketsize /* for error checking */
1436 struct alias_link *lnk;
1437 int iresult = PKT_ALIAS_IGNORED;
1440 pip = (struct ip *)ptr;
1442 /* Defense against mangled packets */
1443 if (ntohs(pip->ip_len) > maxpacketsize
1444 || (pip->ip_hl << 2) > maxpacketsize)
1447 ud = (struct udphdr *)ip_next(pip);
1448 tc = (struct tcphdr *)ip_next(pip);
1449 ic = (struct icmp *)ip_next(pip);
1452 if (pip->ip_p == IPPROTO_UDP)
1453 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1454 ud->uh_dport, ud->uh_sport,
1456 else if (pip->ip_p == IPPROTO_TCP)
1457 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1458 tc->th_dport, tc->th_sport,
1460 else if (pip->ip_p == IPPROTO_ICMP)
1461 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1465 /* Change it from an aliased packet to an unaliased packet */
1467 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1469 struct in_addr original_address;
1470 u_short original_port;
1472 original_address = GetOriginalAddress(lnk);
1473 original_port = GetOriginalPort(lnk);
1475 /* Adjust TCP/UDP checksum */
1476 accumulate = twowords(&pip->ip_src);
1477 accumulate -= twowords(&original_address);
1479 if (pip->ip_p == IPPROTO_UDP) {
1480 accumulate += ud->uh_sport;
1481 accumulate -= original_port;
1482 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1484 accumulate += tc->th_sport;
1485 accumulate -= original_port;
1486 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1489 /* Adjust IP checksum */
1490 DifferentialChecksum(&pip->ip_sum,
1491 &original_address, &pip->ip_src, 2);
1493 /* Un-alias source address and port number */
1494 pip->ip_src = original_address;
1495 if (pip->ip_p == IPPROTO_UDP)
1496 ud->uh_sport = original_port;
1498 tc->th_sport = original_port;
1500 iresult = PKT_ALIAS_OK;
1502 } else if (pip->ip_p == IPPROTO_ICMP) {
1505 struct in_addr original_address;
1506 u_short original_id;
1508 original_address = GetOriginalAddress(lnk);
1509 original_id = GetOriginalPort(lnk);
1511 /* Adjust ICMP checksum */
1512 accumulate = twowords(&pip->ip_src);
1513 accumulate -= twowords(&original_address);
1514 accumulate += ic->icmp_id;
1515 accumulate -= original_id;
1516 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1518 /* Adjust IP checksum */
1519 DifferentialChecksum(&pip->ip_sum,
1520 &original_address, &pip->ip_src, 2);
1522 /* Un-alias source address and port number */
1523 pip->ip_src = original_address;
1524 ic->icmp_id = original_id;
1526 iresult = PKT_ALIAS_OK;
1530 LIBALIAS_UNLOCK(la);
1538 LibAliasRefreshModules(void)
1540 char buf[256], conf[] = "/etc/libalias.conf";
1544 fd = fopen(conf, "r");
1546 err(1, "fopen(%s)", conf);
1548 LibAliasUnLoadAllModule();
1551 fgets(buf, 256, fd);
1556 for (i = 0; i < len; i++)
1557 if (!isspace(buf[i]))
1561 buf[len - 1] = '\0';
1562 kprintf("Loading %s\n", buf);
1563 LibAliasLoadModule(buf);
1570 LibAliasLoadModule(char *path)
1574 struct proto_handler *m;
1578 handle = dlopen (path, RTLD_LAZY);
1580 fkprintf(stderr, "%s\n", dlerror());
1584 p = dlsym(handle, "alias_mod");
1585 if ((error = dlerror()) != NULL) {
1586 fkprintf(stderr, "%s\n", dlerror());
1590 t = kmalloc(sizeof(struct dll),M_ALIAS, M_WAITOK | M_ZERO);
1593 strncpy(t->name, p->name, DLL_LEN);
1595 if (attach_dll(t) == EEXIST) {
1597 fkprintf(stderr, "dll conflict\n");
1601 m = dlsym(t->handle, "handlers");
1602 if ((error = dlerror()) != NULL) {
1603 fkprintf(stderr, "%s\n", error);
1607 LibAliasAttachHandlers(m);
1612 LibAliasUnLoadAllModule(void)
1615 struct proto_handler *p;
1617 /* Unload all modules then reload everything. */
1618 while ((p = first_handler()) != NULL) {
1621 while ((t = walk_dll_chain()) != NULL) {
1632 * m_megapullup() - this function is a big hack.
1633 * Thankfully, it's only used in ng_nat and ipfw+nat.
1635 * It allocates an mbuf with cluster and copies the specified part of the chain
1636 * into cluster, so that it is all contiguous and can be accessed via a plain
1637 * (char *) pointer. This is required, because libalias doesn't know how to
1638 * handle mbuf chains.
1640 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1641 * the input packet, on failure NULL. The input packet is always consumed.
1644 m_megapullup(struct mbuf *m, int len) {
1647 if (len > m->m_pkthdr.len)
1650 /* Do not reallocate packet if it is sequentional,
1651 * writable and has some extra space for expansion.
1652 * XXX: Constant 100bytes is completely empirical. */
1654 if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE)
1657 if (len <= MCLBYTES - RESERVE) {
1658 mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1659 } else if (len < MJUM16BYTES) {
1661 if (len <= MJUMPAGESIZE - RESERVE) {
1662 size = MJUMPAGESIZE;
1663 } else if (len <= MJUM9BYTES - RESERVE) {
1668 mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1677 m_move_pkthdr(mcl, m);
1678 m_copydata(m, 0, len, mtod(mcl, caddr_t));
1679 mcl->m_len = mcl->m_pkthdr.len = len;