b1c8f0f4304812daf76b082603be4036997fb8a5
[dragonfly.git] / sys / net / libalias / alias.c
1 /*-
2  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
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.
37
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.
46
47         Version 1.0 August, 1996  (cjm)
48
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
52          connections.)
53
54         Version 1.2 September 7, 1996 (cjm)
55         Fragment handling error in alias_db.c corrected.
56         (Tom Torrance helped fix this problem.)
57
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.
67
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.)
71
72         Version 1.6 September 18, 1996 (cjm)
73         Simplified ICMP aliasing scheme.  Should now support
74         traceroute from Win95 as well as FreeBSD.
75
76         Version 1.7 January 9, 1997 (cjm)
77         - Out-of-order fragment handling.
78         - IP checksum error fixed for ftp transfers
79           from aliasing host.
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
85           differential).
86
87         Version 2.1 May 1997 (cjm)
88         - Added support for outgoing ICMP error
89           messages.
90         - Added two functions PacketAliasIn2()
91           and PacketAliasOut2() for dynamic address
92           control (e.g. round-robin allocation of
93           incoming packets).
94
95         Version 2.2 July 1997 (cjm)
96         - Rationalized API function names to begin
97           with "PacketAlias..."
98         - Eliminated PacketAliasIn2() and
99           PacketAliasOut2() as poorly conceived.
100
101         Version 2.3 Dec 1998 (dillon)
102         - Major bounds checking additions, see FreeBSD/CVS
103
104         Version 3.1 May, 2000 (salander)
105         - Added hooks to handle PPTP.
106
107         Version 3.2 July, 2000 (salander and satoh)
108         - Added PacketUnaliasOut routine.
109         - Added hooks to handle RTSP/RTP.
110
111         See HISTORY file for additional revisions.
112 */
113
114 #include <sys/param.h>
115 #include <sys/systm.h>
116 #include <sys/mbuf.h>
117
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>
124
125 #include "alias.h"
126 #include "alias_local.h"
127 #include "alias_mod.h"
128
129 static __inline int
130 twowords(void *p)
131 {
132         uint8_t *c = p;
133
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];
137 #else
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];
140 #endif
141         return (s1 + s2);
142 }
143
144 /* TCP Handling Routines
145
146         TcpMonitorIn()  -- These routines monitor TCP connections, and
147         TcpMonitorOut() delete a link when a connection is closed.
148
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
152 a timeout period.
153 */
154
155 /* Local prototypes */
156 static void     TcpMonitorIn(struct ip *, struct alias_link *);
157
158 static void     TcpMonitorOut(struct ip *, struct alias_link *);
159
160
161 static void
162 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
163 {
164         struct tcphdr *tc;
165
166         tc = (struct tcphdr *)ip_next(pip);
167
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);
174                 break;
175         case ALIAS_TCP_STATE_CONNECTED:
176                 if (tc->th_flags & (TH_FIN | TH_RST))
177                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
178                 break;
179         }
180 }
181
182 static void
183 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
184 {
185         struct tcphdr *tc;
186
187         tc = (struct tcphdr *)ip_next(pip);
188
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);
195                 break;
196         case ALIAS_TCP_STATE_CONNECTED:
197                 if (tc->th_flags & (TH_FIN | TH_RST))
198                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
199                 break;
200         }
201 }
202
203
204
205
206
207 /* Protocol Specific Packet Aliasing Routines
208
209         IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
210         IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
211         ProtoAliasIn(), ProtoAliasOut()
212         UdpAliasIn(), UdpAliasOut()
213         TcpAliasIn(), TcpAliasOut()
214
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.
220
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.
224
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
227 packet.
228
229 ICMP error messages are handled by looking at the IP fragment
230 in the data section of the message.
231
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).
237
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.
241
242 All packets go through the aliasing mechanism, whether they come from
243 the gateway machine or other machines on a local area network.
244 */
245
246
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 *);
251
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);
255
256 static int      ProtoAliasIn(struct libalias *, struct ip *);
257 static int      ProtoAliasOut(struct libalias *, struct ip *, int create);
258
259 static int      UdpAliasIn(struct libalias *, struct ip *);
260 static int      UdpAliasOut(struct libalias *, struct ip *, int create);
261
262 static int      TcpAliasIn(struct libalias *, struct ip *);
263 static int      TcpAliasOut(struct libalias *, struct ip *, int, int create);
264
265
266 static int
267 IcmpAliasIn1(struct libalias *la, struct ip *pip)
268 {
269
270         LIBALIAS_LOCK_ASSERT(la);
271 /*
272         De-alias incoming echo and timestamp replies.
273         Alias incoming echo and timestamp requests.
274 */
275         struct alias_link *lnk;
276         struct icmp *ic;
277
278         ic = (struct icmp *)ip_next(pip);
279
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);
282         if (lnk != NULL) {
283                 u_short original_id;
284                 int accumulate;
285
286                 original_id = GetOriginalPort(lnk);
287
288 /* Adjust ICMP checksum */
289                 accumulate = ic->icmp_id;
290                 accumulate -= original_id;
291                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
292
293 /* Put original sequence number back in */
294                 ic->icmp_id = original_id;
295
296 /* Put original address back into IP header */
297                 {
298                         struct in_addr original_address;
299
300                         original_address = GetOriginalAddress(lnk);
301                         DifferentialChecksum(&pip->ip_sum,
302                                 &original_address, &pip->ip_dst, 2);
303                         pip->ip_dst = original_address;
304                 }
305
306                 return (PKT_ALIAS_OK);
307         }
308         return (PKT_ALIAS_IGNORED);
309 }
310
311 static int
312 IcmpAliasIn2(struct libalias *la, struct ip *pip)
313 {
314
315         LIBALIAS_LOCK_ASSERT(la);
316 /*
317         Alias incoming ICMP error messages containing
318         IP header and first 64 bits of datagram.
319 */
320         struct ip *ip;
321         struct icmp *ic, *ic2;
322         struct udphdr *ud;
323         struct tcphdr *tc;
324         struct alias_link *lnk;
325
326         ic = (struct icmp *)ip_next(pip);
327         ip = &ic->icmp_ip;
328
329         ud = (struct udphdr *)ip_next(ip);
330         tc = (struct tcphdr *)ip_next(ip);
331         ic2 = (struct icmp *)ip_next(ip);
332
333         if (ip->ip_p == IPPROTO_UDP)
334                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
335                         ud->uh_dport, ud->uh_sport,
336                         IPPROTO_UDP, 0);
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,
340                         IPPROTO_TCP, 0);
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);
344                 else
345                         lnk = NULL;
346         } else
347                 lnk = NULL;
348
349         if (lnk != NULL) {
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;
354
355                         original_address = GetOriginalAddress(lnk);
356                         original_port = GetOriginalPort(lnk);
357
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);
368
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;
373
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;
381                         u_short original_id;
382
383                         original_address = GetOriginalAddress(lnk);
384                         original_id = GetOriginalPort(lnk);
385
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);
396
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;
401
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;
406                 }
407                 return (PKT_ALIAS_OK);
408         }
409         return (PKT_ALIAS_IGNORED);
410 }
411
412
413 static int
414 IcmpAliasIn(struct libalias *la, struct ip *pip)
415 {
416         int iresult;
417         struct icmp *ic;
418
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);
423
424         ic = (struct icmp *)ip_next(pip);
425
426         iresult = PKT_ALIAS_IGNORED;
427         switch (ic->icmp_type) {
428         case ICMP_ECHOREPLY:
429         case ICMP_TSTAMPREPLY:
430                 if (ic->icmp_code == 0) {
431                         iresult = IcmpAliasIn1(la, pip);
432                 }
433                 break;
434         case ICMP_UNREACH:
435         case ICMP_SOURCEQUENCH:
436         case ICMP_TIMXCEED:
437         case ICMP_PARAMPROB:
438                 iresult = IcmpAliasIn2(la, pip);
439                 break;
440         case ICMP_ECHO:
441         case ICMP_TSTAMP:
442                 iresult = IcmpAliasIn1(la, pip);
443                 break;
444         }
445         return (iresult);
446 }
447
448
449 static int
450 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
451 {
452 /*
453         Alias outgoing echo and timestamp requests.
454         De-alias outgoing echo and timestamp replies.
455 */
456         struct alias_link *lnk;
457         struct icmp *ic;
458
459         LIBALIAS_LOCK_ASSERT(la);
460         ic = (struct icmp *)ip_next(pip);
461
462 /* Save overwritten data for when echo packet returns */
463         lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
464         if (lnk != NULL) {
465                 u_short alias_id;
466                 int accumulate;
467
468                 alias_id = GetAliasPort(lnk);
469
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);
474
475 /* Alias sequence number */
476                 ic->icmp_id = alias_id;
477
478 /* Change source address */
479                 {
480                         struct in_addr alias_address;
481
482                         alias_address = GetAliasAddress(lnk);
483                         DifferentialChecksum(&pip->ip_sum,
484                                 &alias_address, &pip->ip_src, 2);
485                         pip->ip_src = alias_address;
486                 }
487
488                 return (PKT_ALIAS_OK);
489         }
490         return (PKT_ALIAS_IGNORED);
491 }
492
493
494 static int
495 IcmpAliasOut2(struct libalias *la, struct ip *pip)
496 {
497 /*
498         Alias outgoing ICMP error messages containing
499         IP header and first 64 bits of datagram.
500 */
501         struct ip *ip;
502         struct icmp *ic, *ic2;
503         struct udphdr *ud;
504         struct tcphdr *tc;
505         struct alias_link *lnk;
506
507         LIBALIAS_LOCK_ASSERT(la);
508         ic = (struct icmp *)ip_next(pip);
509         ip = &ic->icmp_ip;
510
511         ud = (struct udphdr *)ip_next(ip);
512         tc = (struct tcphdr *)ip_next(ip);
513         ic2 = (struct icmp *)ip_next(ip);
514
515         if (ip->ip_p == IPPROTO_UDP)
516                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
517                         ud->uh_dport, ud->uh_sport,
518                         IPPROTO_UDP, 0);
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,
522                         IPPROTO_TCP, 0);
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);
526                 else
527                         lnk = NULL;
528         } else
529                 lnk = NULL;
530
531         if (lnk != NULL) {
532                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
533                         int accumulate;
534                         struct in_addr alias_address;
535                         u_short alias_port;
536
537                         alias_address = GetAliasAddress(lnk);
538                         alias_port = GetAliasPort(lnk);
539
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);
546
547 /*
548  * Alias address in IP header if it comes from the host
549  * the original TCP/UDP packet was destined for.
550  */
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;
555                         }
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) {
561                         int accumulate;
562                         struct in_addr alias_address;
563                         u_short alias_id;
564
565                         alias_address = GetAliasAddress(lnk);
566                         alias_id = GetAliasPort(lnk);
567
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);
574
575 /*
576  * Alias address in IP header if it comes from the host
577  * the original ICMP message was destined for.
578  */
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;
583                         }
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;
588                 }
589                 return (PKT_ALIAS_OK);
590         }
591         return (PKT_ALIAS_IGNORED);
592 }
593
594
595 static int
596 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
597 {
598         int iresult;
599         struct icmp *ic;
600
601         LIBALIAS_LOCK_ASSERT(la);
602         (void)create;
603
604 /* Return if proxy-only mode is enabled */
605         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
606                 return (PKT_ALIAS_OK);
607
608         ic = (struct icmp *)ip_next(pip);
609
610         iresult = PKT_ALIAS_IGNORED;
611         switch (ic->icmp_type) {
612         case ICMP_ECHO:
613         case ICMP_TSTAMP:
614                 if (ic->icmp_code == 0) {
615                         iresult = IcmpAliasOut1(la, pip, create);
616                 }
617                 break;
618         case ICMP_UNREACH:
619         case ICMP_SOURCEQUENCH:
620         case ICMP_TIMXCEED:
621         case ICMP_PARAMPROB:
622                 iresult = IcmpAliasOut2(la, pip);
623                 break;
624         case ICMP_ECHOREPLY:
625         case ICMP_TSTAMPREPLY:
626                 iresult = IcmpAliasOut1(la, pip, create);
627         }
628         return (iresult);
629 }
630
631
632
633 static int
634 ProtoAliasIn(struct libalias *la, struct ip *pip)
635 {
636 /*
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
640   machine.
641 */
642         struct alias_link *lnk;
643
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);
648
649         lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
650         if (lnk != NULL) {
651                 struct in_addr original_address;
652
653                 original_address = GetOriginalAddress(lnk);
654
655 /* Restore original IP address */
656                 DifferentialChecksum(&pip->ip_sum,
657                         &original_address, &pip->ip_dst, 2);
658                 pip->ip_dst = original_address;
659
660                 return (PKT_ALIAS_OK);
661         }
662         return (PKT_ALIAS_IGNORED);
663 }
664
665
666 static int
667 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
668 {
669 /*
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.
673 */
674         struct alias_link *lnk;
675
676         LIBALIAS_LOCK_ASSERT(la);
677         (void)create;
678
679 /* Return if proxy-only mode is enabled */
680         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
681                 return (PKT_ALIAS_OK);
682
683         lnk = FindProtoOut(la, pip->ip_src, pip->ip_dst, pip->ip_p);
684         if (lnk != NULL) {
685                 struct in_addr alias_address;
686
687                 alias_address = GetAliasAddress(lnk);
688
689 /* Change source address */
690                 DifferentialChecksum(&pip->ip_sum,
691                         &alias_address, &pip->ip_src, 2);
692                 pip->ip_src = alias_address;
693
694                 return (PKT_ALIAS_OK);
695         }
696         return (PKT_ALIAS_IGNORED);
697 }
698
699
700 static int
701 UdpAliasIn(struct libalias *la, struct ip *pip)
702 {
703         struct udphdr *ud;
704         struct alias_link *lnk;
705
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);
710
711         ud = (struct udphdr *)ip_next(pip);
712
713         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
714                 ud->uh_sport, ud->uh_dport,
715                 IPPROTO_UDP, 1);
716         if (lnk != NULL) {
717                 struct in_addr alias_address;
718                 struct in_addr original_address;
719                 u_short alias_port;
720                 int accumulate;
721                 int r = 0, error;
722                 struct alias_data ad = {
723                         .lnk = lnk,
724                         .oaddr = &original_address,
725                         .aaddr = &alias_address,
726                         .aport = &alias_port,
727                         .sport = &ud->uh_sport,
728                         .dport = &ud->uh_dport,
729                         .maxpktsize = 0
730                 };
731
732                 alias_address = GetAliasAddress(lnk);
733                 original_address = GetOriginalAddress(lnk);
734                 alias_port = ud->uh_dport;
735                 ud->uh_dport = GetOriginalPort(lnk);
736
737                 /* Walk out chain. */
738                 error = find_handler(IN, UDP, la, pip, &ad);
739
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);
748                 }
749 /* Restore original IP address */
750                 DifferentialChecksum(&pip->ip_sum,
751                         &original_address, &pip->ip_dst, 2);
752                 pip->ip_dst = original_address;
753
754                 /*
755                  * If we cannot figure out the packet, ignore it.
756                  */
757                 if (r < 0)
758                         return (PKT_ALIAS_IGNORED);
759                 else
760                         return (PKT_ALIAS_OK);
761         }
762         return (PKT_ALIAS_IGNORED);
763 }
764
765 static int
766 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
767 {
768         struct udphdr *ud;
769         struct alias_link *lnk;
770         int error;
771
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);
776
777         ud = (struct udphdr *)ip_next(pip);
778
779         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
780                 ud->uh_sport, ud->uh_dport,
781                 IPPROTO_UDP, create);
782         if (lnk != NULL) {
783                 u_short alias_port;
784                 struct in_addr alias_address;
785                 struct alias_data ad = {
786                         .lnk = lnk,
787                         .oaddr = NULL,
788                         .aaddr = &alias_address,
789                         .aport = &alias_port,
790                         .sport = &ud->uh_sport,
791                         .dport = &ud->uh_dport,
792                         .maxpktsize = 0
793                 };
794
795                 alias_address = GetAliasAddress(lnk);
796                 alias_port = GetAliasPort(lnk);
797
798                 /* Walk out chain. */
799                 error = find_handler(OUT, UDP, la, pip, &ad);
800
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) {
804                         int accumulate;
805
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);
811                 }
812 /* Put alias port in UDP header */
813                 ud->uh_sport = alias_port;
814
815 /* Change source address */
816                 DifferentialChecksum(&pip->ip_sum,
817                         &alias_address, &pip->ip_src, 2);
818                 pip->ip_src = alias_address;
819
820                 return (PKT_ALIAS_OK);
821         }
822         return (PKT_ALIAS_IGNORED);
823 }
824
825
826
827 static int
828 TcpAliasIn(struct libalias *la, struct ip *pip)
829 {
830         struct tcphdr *tc;
831         struct alias_link *lnk;
832
833         LIBALIAS_LOCK_ASSERT(la);
834         tc = (struct tcphdr *)ip_next(pip);
835
836         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
837                 tc->th_sport, tc->th_dport,
838                 IPPROTO_TCP,
839                 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
840         if (lnk != NULL) {
841                 struct in_addr alias_address;
842                 struct in_addr original_address;
843                 struct in_addr proxy_address;
844                 u_short alias_port;
845                 u_short proxy_port;
846                 int accumulate, error;
847
848                 /*
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 [*].
852                  */
853
854                 struct alias_data ad = {
855                         .lnk = lnk,
856                         .oaddr = NULL,
857                         .aaddr = NULL,
858                         .aport = NULL,
859                         .sport = &tc->th_sport,
860                         .dport = &tc->th_dport,
861                         .maxpktsize = 0
862                 };
863
864                 /* Walk out chain. */
865                 error = find_handler(IN, TCP, la, pip, &ad);
866
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);
873
874                 /*
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.
878                  */
879 #if 0
880                                  struct alias_data ad = {
881                                         .lnk = lnk,
882                                         .oaddr = &original_address,
883                                         .aaddr = &alias_address,
884                                         .aport = &alias_port,
885                                         .sport = &ud->uh_sport,
886                                         .dport = &ud->uh_dport,
887                                         .maxpktsize = 0
888                                 };
889
890                                 /* Walk out chain. */
891                                 error = find_handler(la, pip, &ad);
892                                 if (error == EHDNOF)
893                                         kprintf("Protocol handler not found\n");
894 #endif
895
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);
902
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);
911                 }
912 /* See if ACK number needs to be modified */
913                 if (GetAckModified(lnk) == 1) {
914                         int delta;
915
916                         delta = GetDeltaAckIn(pip, lnk);
917                         if (delta != 0) {
918                                 accumulate += twowords(&tc->th_ack);
919                                 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
920                                 accumulate -= twowords(&tc->th_ack);
921                         }
922                 }
923                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
924
925 /* Restore original IP address */
926                 accumulate = twowords(&pip->ip_dst);
927                 pip->ip_dst = original_address;
928                 accumulate -= twowords(&pip->ip_dst);
929
930 /* If this is a transparent proxy packet, then modify the source
931    address */
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);
936                 }
937                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
938
939 /* Monitor TCP connection state */
940                 TcpMonitorIn(pip, lnk);
941
942                 return (PKT_ALIAS_OK);
943         }
944         return (PKT_ALIAS_IGNORED);
945 }
946
947 static int
948 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
949 {
950         int proxy_type, error;
951         u_short dest_port;
952         u_short proxy_server_port;
953         struct in_addr dest_address;
954         struct in_addr proxy_server_address;
955         struct tcphdr *tc;
956         struct alias_link *lnk;
957
958         LIBALIAS_LOCK_ASSERT(la);
959         tc = (struct tcphdr *)ip_next(pip);
960
961         if (create)
962                 proxy_type =
963                         ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
964         else
965                 proxy_type = 0;
966
967         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
968                 return (PKT_ALIAS_OK);
969
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) {
975                 int accumulate;
976
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);
983
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);
988         }
989         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
990                 tc->th_sport, tc->th_dport,
991                 IPPROTO_TCP, create);
992         if (lnk == NULL)
993                 return (PKT_ALIAS_IGNORED);
994         if (lnk != NULL) {
995                 u_short alias_port;
996                 struct in_addr alias_address;
997                 int accumulate;
998                 struct alias_data ad = {
999                         .lnk = lnk,
1000                         .oaddr = NULL,
1001                         .aaddr = &alias_address,
1002                         .aport = &alias_port,
1003                         .sport = &tc->th_sport,
1004                         .dport = &tc->th_dport,
1005                         .maxpktsize = maxpacketsize
1006                 };
1007
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);
1016                 }
1017 /* Get alias address and port */
1018                 alias_port = GetAliasPort(lnk);
1019                 alias_address = GetAliasAddress(lnk);
1020
1021 /* Monitor TCP connection state */
1022                 TcpMonitorOut(pip, lnk);
1023
1024                 /* Walk out chain. */
1025                 error = find_handler(OUT, TCP, la, pip, &ad);
1026
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);
1034
1035 /* Modify sequence number if necessary */
1036                 if (GetAckModified(lnk) == 1) {
1037                         int delta;
1038
1039                         delta = GetDeltaSeqOut(pip, lnk);
1040                         if (delta != 0) {
1041                                 accumulate += twowords(&tc->th_seq);
1042                                 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1043                                 accumulate -= twowords(&tc->th_seq);
1044                         }
1045                 }
1046                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1047
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);
1053
1054                 return (PKT_ALIAS_OK);
1055         }
1056         return (PKT_ALIAS_IGNORED);
1057 }
1058
1059
1060
1061
1062 /* Fragment Handling
1063
1064         FragmentIn()
1065         FragmentOut()
1066
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.
1073 */
1074
1075 /* Local prototypes */
1076 static int      FragmentIn(struct libalias *, struct ip *);
1077 static int      FragmentOut(struct libalias *, struct ip *);
1078
1079
1080 static int
1081 FragmentIn(struct libalias *la, struct ip *pip)
1082 {
1083         struct alias_link *lnk;
1084
1085         LIBALIAS_LOCK_ASSERT(la);
1086         lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1087         if (lnk != NULL) {
1088                 struct in_addr original_address;
1089
1090                 GetFragmentAddr(lnk, &original_address);
1091                 DifferentialChecksum(&pip->ip_sum,
1092                         &original_address, &pip->ip_dst, 2);
1093                 pip->ip_dst = original_address;
1094
1095                 return (PKT_ALIAS_OK);
1096         }
1097         return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1098 }
1099
1100
1101 static int
1102 FragmentOut(struct libalias *la, struct ip *pip)
1103 {
1104         struct in_addr alias_address;
1105
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;
1111
1112         return (PKT_ALIAS_OK);
1113 }
1114
1115
1116
1117
1118
1119
1120 /* Outside World Access
1121
1122         PacketAliasSaveFragment()
1123         PacketAliasGetFragment()
1124         PacketAliasFragmentIn()
1125         PacketAliasIn()
1126         PacketAliasOut()
1127         PacketUnaliasOut()
1128
1129 (prototypes in alias.h)
1130 */
1131
1132
1133 int
1134 LibAliasSaveFragment(struct libalias *la, char *ptr)
1135 {
1136         int iresult;
1137         struct alias_link *lnk;
1138         struct ip *pip;
1139
1140         LIBALIAS_LOCK(la);
1141         pip = (struct ip *)ptr;
1142         lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1143         iresult = PKT_ALIAS_ERROR;
1144         if (lnk != NULL) {
1145                 SetFragmentPtr(lnk, ptr);
1146                 iresult = PKT_ALIAS_OK;
1147         }
1148         LIBALIAS_UNLOCK(la);
1149         return (iresult);
1150 }
1151
1152
1153 char               *
1154 LibAliasGetFragment(struct libalias *la, char *ptr)
1155 {
1156         struct alias_link *lnk;
1157         char *fptr;
1158         struct ip *pip;
1159
1160         LIBALIAS_LOCK(la);
1161         pip = (struct ip *)ptr;
1162         lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1163         if (lnk != NULL) {
1164                 GetFragmentPtr(lnk, &fptr);
1165                 SetFragmentPtr(lnk, NULL);
1166                 SetExpire(lnk, 0);      /* Deletes link */
1167         } else
1168                 fptr = NULL;
1169
1170         LIBALIAS_UNLOCK(la);
1171         return (fptr);
1172 }
1173
1174
1175 void
1176 LibAliasFragmentIn(struct libalias *la, char *ptr,      /* Points to correctly
1177                                                          * de-aliased header
1178                                                          * fragment */
1179         char *ptr_fragment              /* Points to fragment which must be
1180                                  * de-aliased   */
1181 )
1182 {
1183         struct ip *pip;
1184         struct ip *fpip;
1185
1186         LIBALIAS_LOCK(la);
1187         (void)la;
1188         pip = (struct ip *)ptr;
1189         fpip = (struct ip *)ptr_fragment;
1190
1191         DifferentialChecksum(&fpip->ip_sum,
1192                 &pip->ip_dst, &fpip->ip_dst, 2);
1193         fpip->ip_dst = pip->ip_dst;
1194         LIBALIAS_UNLOCK(la);
1195 }
1196
1197 /* Local prototypes */
1198 static int
1199 LibAliasOutLocked(struct libalias *la, char *ptr,
1200                   int maxpacketsize, int create);
1201 static int
1202 LibAliasInLocked(struct libalias *la, char *ptr,
1203                   int maxpacketsize);
1204
1205 int
1206 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1207 {
1208         int res;
1209
1210         LIBALIAS_LOCK(la);
1211         res = LibAliasInLocked(la, ptr, maxpacketsize);
1212         LIBALIAS_UNLOCK(la);
1213         return (res);
1214 }
1215
1216 static int
1217 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1218 {
1219         struct in_addr alias_addr;
1220         struct ip *pip;
1221         int iresult;
1222
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;
1227                 goto getout;
1228         }
1229         HouseKeeping(la);
1230         ClearCheckNewLink(la);
1231         pip = (struct ip *)ptr;
1232         alias_addr = pip->ip_dst;
1233
1234         /* Defense against mangled packets */
1235         if (ntohs(pip->ip_len) > maxpacketsize
1236                 || (pip->ip_hl << 2) > maxpacketsize) {
1237                 iresult = PKT_ALIAS_IGNORED;
1238                 goto getout;
1239         }
1240
1241         iresult = PKT_ALIAS_IGNORED;
1242         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1243                 switch (pip->ip_p) {
1244                 case IPPROTO_ICMP:
1245                         iresult = IcmpAliasIn(la, pip);
1246                         break;
1247                 case IPPROTO_UDP:
1248                         iresult = UdpAliasIn(la, pip);
1249                         break;
1250                 case IPPROTO_TCP:
1251                         iresult = TcpAliasIn(la, pip);
1252                         break;
1253                 case IPPROTO_GRE: {
1254                         int error;
1255                         struct alias_data ad = {
1256                                 .lnk = NULL,
1257                                 .oaddr = NULL,
1258                                 .aaddr = NULL,
1259                                 .aport = NULL,
1260                                 .sport = NULL,
1261                                 .dport = NULL,
1262                                 .maxpktsize = 0
1263                         };
1264
1265                         /* Walk out chain. */
1266                         error = find_handler(IN, IP, la, pip, &ad);
1267                         if (error ==  0)
1268                                 iresult = PKT_ALIAS_OK;
1269                         else
1270                                 iresult = ProtoAliasIn(la, pip);
1271                 }
1272                         break;
1273                 default:
1274                         iresult = ProtoAliasIn(la, pip);
1275                         break;
1276                 }
1277
1278                 if (ntohs(pip->ip_off) & IP_MF) {
1279                         struct alias_link *lnk;
1280
1281                         lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1282                         if (lnk != NULL) {
1283                                 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1284                                 SetFragmentAddr(lnk, pip->ip_dst);
1285                         } else {
1286                                 iresult = PKT_ALIAS_ERROR;
1287                         }
1288                 }
1289         } else {
1290                 iresult = FragmentIn(la, pip);
1291         }
1292
1293 getout:
1294         return (iresult);
1295 }
1296
1297
1298
1299 /* Unregistered address ranges */
1300
1301 /* 10.0.0.0   ->   10.255.255.255 */
1302 #define UNREG_ADDR_A_LOWER 0x0a000000
1303 #define UNREG_ADDR_A_UPPER 0x0affffff
1304
1305 /* 172.16.0.0  ->  172.31.255.255 */
1306 #define UNREG_ADDR_B_LOWER 0xac100000
1307 #define UNREG_ADDR_B_UPPER 0xac1fffff
1308
1309 /* 192.168.0.0 -> 192.168.255.255 */
1310 #define UNREG_ADDR_C_LOWER 0xc0a80000
1311 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1312
1313 int
1314 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1315 {
1316         int res;
1317
1318         LIBALIAS_LOCK(la);
1319         res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1320         LIBALIAS_UNLOCK(la);
1321         return (res);
1322 }
1323
1324 int
1325 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1326 {
1327         int res;
1328
1329         LIBALIAS_LOCK(la);
1330         res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1331         LIBALIAS_UNLOCK(la);
1332         return (res);
1333 }
1334
1335 static int
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 ? */
1340 )
1341 {
1342         int iresult;
1343         struct in_addr addr_save;
1344         struct ip *pip;
1345
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;
1350                 goto getout;
1351         }
1352         HouseKeeping(la);
1353         ClearCheckNewLink(la);
1354         pip = (struct ip *)ptr;
1355
1356         /* Defense against mangled packets */
1357         if (ntohs(pip->ip_len) > maxpacketsize
1358                 || (pip->ip_hl << 2) > maxpacketsize) {
1359                 iresult = PKT_ALIAS_IGNORED;
1360                 goto getout;
1361         }
1362
1363         addr_save = GetDefaultAliasAddress(la);
1364         if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1365                 u_long addr;
1366                 int iclass;
1367
1368                 iclass = 0;
1369                 addr = ntohl(pip->ip_src.s_addr);
1370                 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1371                         iclass = 3;
1372                 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1373                         iclass = 2;
1374                 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1375                         iclass = 1;
1376
1377                 if (iclass == 0) {
1378                         SetDefaultAliasAddress(la, pip->ip_src);
1379                 }
1380         } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1381                 SetDefaultAliasAddress(la, pip->ip_src);
1382         }
1383         iresult = PKT_ALIAS_IGNORED;
1384         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1385                 switch (pip->ip_p) {
1386                 case IPPROTO_ICMP:
1387                         iresult = IcmpAliasOut(la, pip, create);
1388                         break;
1389                 case IPPROTO_UDP:
1390                         iresult = UdpAliasOut(la, pip, create);
1391                         break;
1392                         case IPPROTO_TCP:
1393                         iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1394                         break;
1395                 case IPPROTO_GRE: {
1396                         int error;
1397                         struct alias_data ad = {
1398                                 .lnk = NULL,
1399                                 .oaddr = NULL,
1400                                 .aaddr = NULL,
1401                                 .aport = NULL,
1402                                 .sport = NULL,
1403                                 .dport = NULL,
1404                                 .maxpktsize = 0
1405                         };
1406                         /* Walk out chain. */
1407                         error = find_handler(OUT, IP, la, pip, &ad);
1408                         if (error == 0)
1409                                 iresult = PKT_ALIAS_OK;
1410                         else
1411                                 iresult = ProtoAliasOut(la, pip, create);
1412                 }
1413                         break;
1414                 default:
1415                         iresult = ProtoAliasOut(la, pip, create);
1416                         break;
1417                 }
1418         } else {
1419                 iresult = FragmentOut(la, pip);
1420         }
1421
1422         SetDefaultAliasAddress(la, addr_save);
1423 getout:
1424         return (iresult);
1425 }
1426
1427 int
1428 LibAliasUnaliasOut(struct libalias *la, char *ptr,      /* valid IP packet */
1429         int maxpacketsize               /* for error checking */
1430 )
1431 {
1432         struct ip *pip;
1433         struct icmp *ic;
1434         struct udphdr *ud;
1435         struct tcphdr *tc;
1436         struct alias_link *lnk;
1437         int iresult = PKT_ALIAS_IGNORED;
1438
1439         LIBALIAS_LOCK(la);
1440         pip = (struct ip *)ptr;
1441
1442         /* Defense against mangled packets */
1443         if (ntohs(pip->ip_len) > maxpacketsize
1444                 || (pip->ip_hl << 2) > maxpacketsize)
1445                 goto getout;
1446
1447         ud = (struct udphdr *)ip_next(pip);
1448         tc = (struct tcphdr *)ip_next(pip);
1449         ic = (struct icmp *)ip_next(pip);
1450
1451         /* Find a link */
1452         if (pip->ip_p == IPPROTO_UDP)
1453                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1454                         ud->uh_dport, ud->uh_sport,
1455                         IPPROTO_UDP, 0);
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,
1459                         IPPROTO_TCP, 0);
1460         else if (pip->ip_p == IPPROTO_ICMP)
1461                 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1462         else
1463                 lnk = NULL;
1464
1465         /* Change it from an aliased packet to an unaliased packet */
1466         if (lnk != NULL) {
1467                 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1468                         int accumulate;
1469                         struct in_addr original_address;
1470                         u_short original_port;
1471
1472                         original_address = GetOriginalAddress(lnk);
1473                         original_port = GetOriginalPort(lnk);
1474
1475                         /* Adjust TCP/UDP checksum */
1476                         accumulate = twowords(&pip->ip_src);
1477                         accumulate -= twowords(&original_address);
1478
1479                         if (pip->ip_p == IPPROTO_UDP) {
1480                                 accumulate += ud->uh_sport;
1481                                 accumulate -= original_port;
1482                                 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1483                         } else {
1484                                 accumulate += tc->th_sport;
1485                                 accumulate -= original_port;
1486                                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1487                         }
1488
1489                         /* Adjust IP checksum */
1490                         DifferentialChecksum(&pip->ip_sum,
1491                                 &original_address, &pip->ip_src, 2);
1492
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;
1497                         else
1498                                 tc->th_sport = original_port;
1499
1500                         iresult = PKT_ALIAS_OK;
1501
1502                 } else if (pip->ip_p == IPPROTO_ICMP) {
1503
1504                         int accumulate;
1505                         struct in_addr original_address;
1506                         u_short original_id;
1507
1508                         original_address = GetOriginalAddress(lnk);
1509                         original_id = GetOriginalPort(lnk);
1510
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);
1517
1518                         /* Adjust IP checksum */
1519                         DifferentialChecksum(&pip->ip_sum,
1520                                 &original_address, &pip->ip_src, 2);
1521
1522                         /* Un-alias source address and port number */
1523                         pip->ip_src = original_address;
1524                         ic->icmp_id = original_id;
1525
1526                         iresult = PKT_ALIAS_OK;
1527                 }
1528         }
1529 getout:
1530         LIBALIAS_UNLOCK(la);
1531         return (iresult);
1532
1533 }
1534
1535 #ifndef _KERNEL
1536
1537 int
1538 LibAliasRefreshModules(void)
1539 {
1540         char buf[256], conf[] = "/etc/libalias.conf";
1541         FILE *fd;
1542         int i, len;
1543
1544         fd = fopen(conf, "r");
1545         if (fd == NULL)
1546                 err(1, "fopen(%s)", conf);
1547
1548         LibAliasUnLoadAllModule();
1549
1550         for (;;) {
1551                 fgets(buf, 256, fd);
1552                 if feof(fd)
1553                                 break;
1554                 len = strlen(buf);
1555                 if (len > 1) {
1556                         for (i = 0; i < len; i++)
1557                                 if (!isspace(buf[i]))
1558                                         break;
1559                         if (buf[i] == '#')
1560                                 continue;
1561                         buf[len - 1] = '\0';
1562                         kprintf("Loading %s\n", buf);
1563                         LibAliasLoadModule(buf);
1564                 }
1565         }
1566         return (0);
1567 }
1568
1569 int
1570 LibAliasLoadModule(char *path)
1571 {
1572         struct dll *t;
1573         void *handle;
1574         struct proto_handler *m;
1575                 const char *error;
1576         moduledata_t *p;
1577
1578                 handle = dlopen (path, RTLD_LAZY);
1579                 if (!handle) {
1580                 fkprintf(stderr, "%s\n", dlerror());
1581                 return (EINVAL);
1582                 }
1583
1584         p = dlsym(handle, "alias_mod");
1585                 if ((error = dlerror()) != NULL)  {
1586                 fkprintf(stderr, "%s\n", dlerror());
1587                 return (EINVAL);
1588                 }
1589
1590         t = kmalloc(sizeof(struct dll),M_ALIAS, M_WAITOK | M_ZERO);
1591         if (t == NULL)
1592                 return (ENOMEM);
1593         strncpy(t->name, p->name, DLL_LEN);
1594         t->handle = handle;
1595         if (attach_dll(t) == EEXIST) {
1596                 kfree(t,M_ALIAS);
1597                 fkprintf(stderr, "dll conflict\n");
1598                 return (EEXIST);
1599         }
1600
1601                 m = dlsym(t->handle, "handlers");
1602                 if ((error = dlerror()) != NULL)  {
1603                 fkprintf(stderr, "%s\n", error);
1604                 return (EINVAL);
1605         }
1606
1607         LibAliasAttachHandlers(m);
1608         return (0);
1609 }
1610
1611 int
1612 LibAliasUnLoadAllModule(void)
1613 {
1614         struct dll *t;
1615         struct proto_handler *p;
1616
1617         /* Unload all modules then reload everything. */
1618         while ((p = first_handler()) != NULL) {
1619                 detach_handler(p);
1620         }
1621         while ((t = walk_dll_chain()) != NULL) {
1622                 dlclose(t->handle);
1623                 kfree(t,M_ALIAS);
1624         }
1625         return (1);
1626 }
1627
1628 #endif
1629
1630 #ifdef _KERNEL
1631 /*
1632  * m_megapullup() - this function is a big hack.
1633  * Thankfully, it's only used in ng_nat and ipfw+nat.
1634  *
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.
1639  *
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.
1642  */
1643 struct mbuf *
1644 m_megapullup(struct mbuf *m, int len) {
1645         struct mbuf *mcl;
1646
1647         if (len > m->m_pkthdr.len)
1648                 goto bad;
1649
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. */
1653 #define RESERVE 100
1654         if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE)
1655                 return (m);
1656         /*
1657         if (len <= MCLBYTES - RESERVE) {
1658                 mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1659         } else if (len < MJUM16BYTES) {
1660                 int size;
1661                 if (len <= MJUMPAGESIZE - RESERVE) {
1662                         size = MJUMPAGESIZE;
1663                 } else if (len <= MJUM9BYTES - RESERVE) {
1664                         size = MJUM9BYTES;
1665                 } else {
1666                         size = MJUM16BYTES;
1667                 };
1668                 mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1669         } else {
1670                 goto bad;
1671         }
1672         */
1673         mcl = NULL;
1674         if (mcl == NULL)
1675                 goto bad;
1676
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;
1680         m_freem(m);
1681
1682         return (mcl);
1683 bad:
1684         m_freem(m);
1685         return (NULL);
1686 }
1687 #endif