]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias.c
Mark more nodes as CTLFLAG_MPSAFE or CTLFLAG_NEEDGIANT (17 of many)
[FreeBSD/FreeBSD.git] / sys / netinet / libalias / alias.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /*
33     Alias.c provides supervisory control for the functions of the
34     packet aliasing software.  It consists of routines to monitor
35     TCP connection state, protocol-specific aliasing routines,
36     fragment handling and the following outside world functional
37     interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
38     PacketAliasIn and PacketAliasOut.
39
40     The other C program files are briefly described. The data
41     structure framework which holds information needed to translate
42     packets is encapsulated in alias_db.c.  Data is accessed by
43     function calls, so other segments of the program need not know
44     about the underlying data structures.  Alias_ftp.c contains
45     special code for modifying the ftp PORT command used to establish
46     data connections, while alias_irc.c does the same for IRC
47     DCC. Alias_util.c contains a few utility routines.
48
49     Version 1.0 August, 1996  (cjm)
50
51     Version 1.1 August 20, 1996  (cjm)
52         PPP host accepts incoming connections for ports 0 to 1023.
53         (Gary Roberts pointed out the need to handle incoming
54          connections.)
55
56     Version 1.2 September 7, 1996 (cjm)
57         Fragment handling error in alias_db.c corrected.
58         (Tom Torrance helped fix this problem.)
59
60     Version 1.4 September 16, 1996 (cjm)
61         - A more generalized method for handling incoming
62           connections, without the 0-1023 restriction, is
63           implemented in alias_db.c
64         - Improved ICMP support in alias.c.  Traceroute
65           packet streams can now be correctly aliased.
66         - TCP connection closing logic simplified in
67           alias.c and now allows for additional 1 minute
68           "grace period" after FIN or RST is observed.
69
70     Version 1.5 September 17, 1996 (cjm)
71         Corrected error in handling incoming UDP packets with 0 checksum.
72         (Tom Torrance helped fix this problem.)
73
74     Version 1.6 September 18, 1996 (cjm)
75         Simplified ICMP aliasing scheme.  Should now support
76         traceroute from Win95 as well as FreeBSD.
77
78     Version 1.7 January 9, 1997 (cjm)
79         - Out-of-order fragment handling.
80         - IP checksum error fixed for ftp transfers
81           from aliasing host.
82         - Integer return codes added to all
83           aliasing/de-aliasing functions.
84         - Some obsolete comments cleaned up.
85         - Differential checksum computations for
86           IP header (TCP, UDP and ICMP were already
87           differential).
88
89     Version 2.1 May 1997 (cjm)
90         - Added support for outgoing ICMP error
91           messages.
92         - Added two functions PacketAliasIn2()
93           and PacketAliasOut2() for dynamic address
94           control (e.g. round-robin allocation of
95           incoming packets).
96
97     Version 2.2 July 1997 (cjm)
98         - Rationalized API function names to begin
99           with "PacketAlias..."
100         - Eliminated PacketAliasIn2() and
101           PacketAliasOut2() as poorly conceived.
102
103     Version 2.3 Dec 1998 (dillon)
104         - Major bounds checking additions, see FreeBSD/CVS
105
106     Version 3.1 May, 2000 (salander)
107         - Added hooks to handle PPTP.
108
109     Version 3.2 July, 2000 (salander and satoh)
110         - Added PacketUnaliasOut routine.
111         - Added hooks to handle RTSP/RTP.
112
113     See HISTORY file for additional revisions.
114 */
115
116 #ifdef _KERNEL
117 #include <sys/param.h>
118 #include <sys/systm.h>
119 #include <sys/mbuf.h>
120 #include <sys/sysctl.h>
121 #else
122 #include <sys/types.h>
123 #include <stdlib.h>
124 #include <stdio.h>
125 #include <ctype.h>
126 #include <dlfcn.h>
127 #include <errno.h>
128 #include <string.h>
129 #endif
130
131 #include <netinet/in_systm.h>
132 #include <netinet/in.h>
133 #include <netinet/ip.h>
134 #include <netinet/ip_icmp.h>
135 #include <netinet/tcp.h>
136 #include <netinet/udp.h>
137
138 #ifdef _KERNEL
139 #include <netinet/libalias/alias.h>
140 #include <netinet/libalias/alias_local.h>
141 #include <netinet/libalias/alias_mod.h>
142 #else
143 #include <err.h>
144 #include "alias.h"
145 #include "alias_local.h"
146 #include "alias_mod.h"
147 #endif
148
149 /* 
150  * Define libalias SYSCTL Node
151  */
152 #ifdef SYSCTL_NODE
153
154 SYSCTL_DECL(_net_inet);
155 SYSCTL_DECL(_net_inet_ip);
156 SYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
157     "Libalias sysctl API");
158
159 #endif
160
161 static __inline int
162 twowords(void *p)
163 {
164         uint8_t *c = p;
165
166 #if BYTE_ORDER == LITTLE_ENDIAN
167         uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
168         uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
169 #else
170         uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
171         uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
172 #endif
173         return (s1 + s2);
174 }
175
176 /* TCP Handling Routines
177
178     TcpMonitorIn()  -- These routines monitor TCP connections, and
179     TcpMonitorOut()    delete a link when a connection is closed.
180
181 These routines look for SYN, FIN and RST flags to determine when TCP
182 connections open and close.  When a TCP connection closes, the data
183 structure containing packet aliasing information is deleted after
184 a timeout period.
185 */
186
187 /* Local prototypes */
188 static void     TcpMonitorIn(u_char, struct alias_link *);
189
190 static void     TcpMonitorOut(u_char, struct alias_link *);
191
192
193 static void
194 TcpMonitorIn(u_char th_flags, struct alias_link *lnk)
195 {
196
197         switch (GetStateIn(lnk)) {
198         case ALIAS_TCP_STATE_NOT_CONNECTED:
199                 if (th_flags & TH_RST)
200                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
201                 else if (th_flags & TH_SYN)
202                         SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
203                 break;
204         case ALIAS_TCP_STATE_CONNECTED:
205                 if (th_flags & (TH_FIN | TH_RST))
206                         SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
207                 break;
208         }
209 }
210
211 static void
212 TcpMonitorOut(u_char th_flags, struct alias_link *lnk)
213 {
214
215         switch (GetStateOut(lnk)) {
216         case ALIAS_TCP_STATE_NOT_CONNECTED:
217                 if (th_flags & TH_RST)
218                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
219                 else if (th_flags & TH_SYN)
220                         SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
221                 break;
222         case ALIAS_TCP_STATE_CONNECTED:
223                 if (th_flags & (TH_FIN | TH_RST))
224                         SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
225                 break;
226         }
227 }
228
229
230
231
232
233 /* Protocol Specific Packet Aliasing Routines
234
235     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
236     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
237     ProtoAliasIn(), ProtoAliasOut()
238     UdpAliasIn(), UdpAliasOut()
239     TcpAliasIn(), TcpAliasOut()
240
241 These routines handle protocol specific details of packet aliasing.
242 One may observe a certain amount of repetitive arithmetic in these
243 functions, the purpose of which is to compute a revised checksum
244 without actually summing over the entire data packet, which could be
245 unnecessarily time consuming.
246
247 The purpose of the packet aliasing routines is to replace the source
248 address of the outgoing packet and then correctly put it back for
249 any incoming packets.  For TCP and UDP, ports are also re-mapped.
250
251 For ICMP echo/timestamp requests and replies, the following scheme
252 is used: the ID number is replaced by an alias for the outgoing
253 packet.
254
255 ICMP error messages are handled by looking at the IP fragment
256 in the data section of the message.
257
258 For TCP and UDP protocols, a port number is chosen for an outgoing
259 packet, and then incoming packets are identified by IP address and
260 port numbers.  For TCP packets, there is additional logic in the event
261 that sequence and ACK numbers have been altered (as in the case for
262 FTP data port commands).
263
264 The port numbers used by the packet aliasing module are not true
265 ports in the Unix sense.  No sockets are actually bound to ports.
266 They are more correctly thought of as placeholders.
267
268 All packets go through the aliasing mechanism, whether they come from
269 the gateway machine or other machines on a local area network.
270 */
271
272
273 /* Local prototypes */
274 static int      IcmpAliasIn1(struct libalias *, struct ip *);
275 static int      IcmpAliasIn2(struct libalias *, struct ip *);
276 static int      IcmpAliasIn(struct libalias *, struct ip *);
277
278 static int      IcmpAliasOut1(struct libalias *, struct ip *, int create);
279 static int      IcmpAliasOut2(struct libalias *, struct ip *);
280 static int      IcmpAliasOut(struct libalias *, struct ip *, int create);
281
282 static int      ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
283                     struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum);
284 static int      ProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 
285                     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, 
286                     int create);
287
288 static int      UdpAliasIn(struct libalias *, struct ip *);
289 static int      UdpAliasOut(struct libalias *, struct ip *, int, int create);
290
291 static int      TcpAliasIn(struct libalias *, struct ip *);
292 static int      TcpAliasOut(struct libalias *, struct ip *, int, int create);
293
294
295 static int
296 IcmpAliasIn1(struct libalias *la, struct ip *pip)
297 {
298
299         LIBALIAS_LOCK_ASSERT(la);
300 /*
301     De-alias incoming echo and timestamp replies.
302     Alias incoming echo and timestamp requests.
303 */
304         struct alias_link *lnk;
305         struct icmp *ic;
306
307         ic = (struct icmp *)ip_next(pip);
308
309 /* Get source address from ICMP data field and restore original data */
310         lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
311         if (lnk != NULL) {
312                 u_short original_id;
313                 int accumulate;
314
315                 original_id = GetOriginalPort(lnk);
316
317 /* Adjust ICMP checksum */
318                 accumulate = ic->icmp_id;
319                 accumulate -= original_id;
320                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
321
322 /* Put original sequence number back in */
323                 ic->icmp_id = original_id;
324
325 /* Put original address back into IP header */
326                 {
327                         struct in_addr original_address;
328
329                         original_address = GetOriginalAddress(lnk);
330                         DifferentialChecksum(&pip->ip_sum,
331                             &original_address, &pip->ip_dst, 2);
332                         pip->ip_dst = original_address;
333                 }
334
335                 return (PKT_ALIAS_OK);
336         }
337         return (PKT_ALIAS_IGNORED);
338 }
339
340 static int
341 IcmpAliasIn2(struct libalias *la, struct ip *pip)
342 {
343
344         LIBALIAS_LOCK_ASSERT(la);
345 /*
346     Alias incoming ICMP error messages containing
347     IP header and first 64 bits of datagram.
348 */
349         struct ip *ip;
350         struct icmp *ic, *ic2;
351         struct udphdr *ud;
352         struct tcphdr *tc;
353         struct alias_link *lnk;
354
355         ic = (struct icmp *)ip_next(pip);
356         ip = &ic->icmp_ip;
357
358         ud = (struct udphdr *)ip_next(ip);
359         tc = (struct tcphdr *)ip_next(ip);
360         ic2 = (struct icmp *)ip_next(ip);
361
362         if (ip->ip_p == IPPROTO_UDP)
363                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
364                     ud->uh_dport, ud->uh_sport,
365                     IPPROTO_UDP, 0);
366         else if (ip->ip_p == IPPROTO_TCP)
367                 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
368                     tc->th_dport, tc->th_sport,
369                     IPPROTO_TCP, 0);
370         else if (ip->ip_p == IPPROTO_ICMP) {
371                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
372                         lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
373                 else
374                         lnk = NULL;
375         } else
376                 lnk = NULL;
377
378         if (lnk != NULL) {
379                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
380                         int accumulate, accumulate2;
381                         struct in_addr original_address;
382                         u_short original_port;
383
384                         original_address = GetOriginalAddress(lnk);
385                         original_port = GetOriginalPort(lnk);
386
387 /* Adjust ICMP checksum */
388                         accumulate = twowords(&ip->ip_src);
389                         accumulate -= twowords(&original_address);
390                         accumulate += ud->uh_sport;
391                         accumulate -= original_port;
392                         accumulate2 = accumulate;
393                         accumulate2 += ip->ip_sum;
394                         ADJUST_CHECKSUM(accumulate, ip->ip_sum);
395                         accumulate2 -= ip->ip_sum;
396                         ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
397
398 /* Un-alias address in IP header */
399                         DifferentialChecksum(&pip->ip_sum,
400                             &original_address, &pip->ip_dst, 2);
401                         pip->ip_dst = original_address;
402
403 /* Un-alias address and port number of original IP packet
404 fragment contained in ICMP data section */
405                         ip->ip_src = original_address;
406                         ud->uh_sport = original_port;
407                 } else if (ip->ip_p == IPPROTO_ICMP) {
408                         int accumulate, accumulate2;
409                         struct in_addr original_address;
410                         u_short original_id;
411
412                         original_address = GetOriginalAddress(lnk);
413                         original_id = GetOriginalPort(lnk);
414
415 /* Adjust ICMP checksum */
416                         accumulate = twowords(&ip->ip_src);
417                         accumulate -= twowords(&original_address);
418                         accumulate += ic2->icmp_id;
419                         accumulate -= original_id;
420                         accumulate2 = accumulate;
421                         accumulate2 += ip->ip_sum;
422                         ADJUST_CHECKSUM(accumulate, ip->ip_sum);
423                         accumulate2 -= ip->ip_sum;
424                         ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
425
426 /* Un-alias address in IP header */
427                         DifferentialChecksum(&pip->ip_sum,
428                             &original_address, &pip->ip_dst, 2);
429                         pip->ip_dst = original_address;
430
431 /* Un-alias address of original IP packet and sequence number of
432    embedded ICMP datagram */
433                         ip->ip_src = original_address;
434                         ic2->icmp_id = original_id;
435                 }
436                 return (PKT_ALIAS_OK);
437         }
438         return (PKT_ALIAS_IGNORED);
439 }
440
441
442 static int
443 IcmpAliasIn(struct libalias *la, struct ip *pip)
444 {
445         int iresult;
446         struct icmp *ic;
447
448         LIBALIAS_LOCK_ASSERT(la);
449 /* Return if proxy-only mode is enabled */
450         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
451                 return (PKT_ALIAS_OK);
452
453         ic = (struct icmp *)ip_next(pip);
454
455         iresult = PKT_ALIAS_IGNORED;
456         switch (ic->icmp_type) {
457         case ICMP_ECHOREPLY:
458         case ICMP_TSTAMPREPLY:
459                 if (ic->icmp_code == 0) {
460                         iresult = IcmpAliasIn1(la, pip);
461                 }
462                 break;
463         case ICMP_UNREACH:
464         case ICMP_SOURCEQUENCH:
465         case ICMP_TIMXCEED:
466         case ICMP_PARAMPROB:
467                 iresult = IcmpAliasIn2(la, pip);
468                 break;
469         case ICMP_ECHO:
470         case ICMP_TSTAMP:
471                 iresult = IcmpAliasIn1(la, pip);
472                 break;
473         }
474         return (iresult);
475 }
476
477
478 static int
479 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
480 {
481 /*
482     Alias outgoing echo and timestamp requests.
483     De-alias outgoing echo and timestamp replies.
484 */
485         struct alias_link *lnk;
486         struct icmp *ic;
487
488         LIBALIAS_LOCK_ASSERT(la);
489         ic = (struct icmp *)ip_next(pip);
490
491 /* Save overwritten data for when echo packet returns */
492         lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
493         if (lnk != NULL) {
494                 u_short alias_id;
495                 int accumulate;
496
497                 alias_id = GetAliasPort(lnk);
498
499 /* Since data field is being modified, adjust ICMP checksum */
500                 accumulate = ic->icmp_id;
501                 accumulate -= alias_id;
502                 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
503
504 /* Alias sequence number */
505                 ic->icmp_id = alias_id;
506
507 /* Change source address */
508                 {
509                         struct in_addr alias_address;
510
511                         alias_address = GetAliasAddress(lnk);
512                         DifferentialChecksum(&pip->ip_sum,
513                             &alias_address, &pip->ip_src, 2);
514                         pip->ip_src = alias_address;
515                 }
516
517                 return (PKT_ALIAS_OK);
518         }
519         return (PKT_ALIAS_IGNORED);
520 }
521
522
523 static int
524 IcmpAliasOut2(struct libalias *la, struct ip *pip)
525 {
526 /*
527     Alias outgoing ICMP error messages containing
528     IP header and first 64 bits of datagram.
529 */
530         struct ip *ip;
531         struct icmp *ic, *ic2;
532         struct udphdr *ud;
533         struct tcphdr *tc;
534         struct alias_link *lnk;
535
536         LIBALIAS_LOCK_ASSERT(la);
537         ic = (struct icmp *)ip_next(pip);
538         ip = &ic->icmp_ip;
539
540         ud = (struct udphdr *)ip_next(ip);
541         tc = (struct tcphdr *)ip_next(ip);
542         ic2 = (struct icmp *)ip_next(ip);
543
544         if (ip->ip_p == IPPROTO_UDP)
545                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
546                     ud->uh_dport, ud->uh_sport,
547                     IPPROTO_UDP, 0);
548         else if (ip->ip_p == IPPROTO_TCP)
549                 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
550                     tc->th_dport, tc->th_sport,
551                     IPPROTO_TCP, 0);
552         else if (ip->ip_p == IPPROTO_ICMP) {
553                 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
554                         lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
555                 else
556                         lnk = NULL;
557         } else
558                 lnk = NULL;
559
560         if (lnk != NULL) {
561                 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
562                         int accumulate;
563                         struct in_addr alias_address;
564                         u_short alias_port;
565
566                         alias_address = GetAliasAddress(lnk);
567                         alias_port = GetAliasPort(lnk);
568
569 /* Adjust ICMP checksum */
570                         accumulate = twowords(&ip->ip_dst);
571                         accumulate -= twowords(&alias_address);
572                         accumulate += ud->uh_dport;
573                         accumulate -= alias_port;
574                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
575
576 /*
577  * Alias address in IP header if it comes from the host
578  * the original TCP/UDP packet was destined for.
579  */
580                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
581                                 DifferentialChecksum(&pip->ip_sum,
582                                     &alias_address, &pip->ip_src, 2);
583                                 pip->ip_src = alias_address;
584                         }
585 /* Alias address and port number of original IP packet
586 fragment contained in ICMP data section */
587                         ip->ip_dst = alias_address;
588                         ud->uh_dport = alias_port;
589                 } else if (ip->ip_p == IPPROTO_ICMP) {
590                         int accumulate;
591                         struct in_addr alias_address;
592                         u_short alias_id;
593
594                         alias_address = GetAliasAddress(lnk);
595                         alias_id = GetAliasPort(lnk);
596
597 /* Adjust ICMP checksum */
598                         accumulate = twowords(&ip->ip_dst);
599                         accumulate -= twowords(&alias_address);
600                         accumulate += ic2->icmp_id;
601                         accumulate -= alias_id;
602                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
603
604 /*
605  * Alias address in IP header if it comes from the host
606  * the original ICMP message was destined for.
607  */
608                         if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
609                                 DifferentialChecksum(&pip->ip_sum,
610                                     &alias_address, &pip->ip_src, 2);
611                                 pip->ip_src = alias_address;
612                         }
613 /* Alias address of original IP packet and sequence number of
614    embedded ICMP datagram */
615                         ip->ip_dst = alias_address;
616                         ic2->icmp_id = alias_id;
617                 }
618                 return (PKT_ALIAS_OK);
619         }
620         return (PKT_ALIAS_IGNORED);
621 }
622
623
624 static int
625 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
626 {
627         int iresult;
628         struct icmp *ic;
629
630         LIBALIAS_LOCK_ASSERT(la);
631         (void)create;
632
633 /* Return if proxy-only mode is enabled */
634         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
635                 return (PKT_ALIAS_OK);
636
637         ic = (struct icmp *)ip_next(pip);
638
639         iresult = PKT_ALIAS_IGNORED;
640         switch (ic->icmp_type) {
641         case ICMP_ECHO:
642         case ICMP_TSTAMP:
643                 if (ic->icmp_code == 0) {
644                         iresult = IcmpAliasOut1(la, pip, create);
645                 }
646                 break;
647         case ICMP_UNREACH:
648         case ICMP_SOURCEQUENCH:
649         case ICMP_TIMXCEED:
650         case ICMP_PARAMPROB:
651                 iresult = IcmpAliasOut2(la, pip);
652                 break;
653         case ICMP_ECHOREPLY:
654         case ICMP_TSTAMPREPLY:
655                 iresult = IcmpAliasOut1(la, pip, create);
656         }
657         return (iresult);
658 }
659
660 static int
661 ProtoAliasIn(struct libalias *la, struct in_addr ip_src, 
662     struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum)
663 {
664 /*
665   Handle incoming IP packets. The
666   only thing which is done in this case is to alias
667   the dest IP address of the packet to our inside
668   machine.
669 */
670         struct alias_link *lnk;
671
672         LIBALIAS_LOCK_ASSERT(la);
673 /* Return if proxy-only mode is enabled */
674         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
675                 return (PKT_ALIAS_OK);
676
677         lnk = FindProtoIn(la, ip_src, *ip_dst, ip_p);
678         if (lnk != NULL) {
679                 struct in_addr original_address;
680
681                 original_address = GetOriginalAddress(lnk);
682
683 /* Restore original IP address */
684                 DifferentialChecksum(ip_sum,
685                     &original_address, ip_dst, 2);
686                 *ip_dst = original_address;
687
688                 return (PKT_ALIAS_OK);
689         }
690         return (PKT_ALIAS_IGNORED);
691 }
692
693 static int
694 ProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 
695     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
696 {
697 /*
698   Handle outgoing IP packets. The
699   only thing which is done in this case is to alias
700   the source IP address of the packet.
701 */
702         struct alias_link *lnk;
703
704         LIBALIAS_LOCK_ASSERT(la);
705
706 /* Return if proxy-only mode is enabled */
707         if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
708                 return (PKT_ALIAS_OK);
709
710         if (!create)
711                 return (PKT_ALIAS_IGNORED);
712
713         lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p);
714         if (lnk != NULL) {
715                 struct in_addr alias_address;
716
717                 alias_address = GetAliasAddress(lnk);
718
719 /* Change source address */
720                 DifferentialChecksum(ip_sum,
721                     &alias_address, ip_src, 2);
722                 *ip_src = alias_address;
723
724                 return (PKT_ALIAS_OK);
725         }
726         return (PKT_ALIAS_IGNORED);
727 }
728
729
730 static int
731 UdpAliasIn(struct libalias *la, struct ip *pip)
732 {
733         struct udphdr *ud;
734         struct alias_link *lnk;
735
736         LIBALIAS_LOCK_ASSERT(la);
737
738         ud = (struct udphdr *)ip_next(pip);
739
740         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
741             ud->uh_sport, ud->uh_dport,
742             IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
743         if (lnk != NULL) {
744                 struct in_addr alias_address;
745                 struct in_addr original_address;
746                 struct in_addr proxy_address;
747                 u_short alias_port;
748                 u_short proxy_port;
749                 int accumulate;
750                 int error;
751                 struct alias_data ad = {
752                         .lnk = lnk, 
753                         .oaddr = &original_address, 
754                         .aaddr = &alias_address,
755                         .aport = &alias_port,
756                         .sport = &ud->uh_sport,
757                         .dport = &ud->uh_dport,
758                         .maxpktsize = 0
759                 };
760
761                 alias_address = GetAliasAddress(lnk);
762                 original_address = GetOriginalAddress(lnk);
763                 proxy_address = GetProxyAddress(lnk);
764                 alias_port = ud->uh_dport;
765                 ud->uh_dport = GetOriginalPort(lnk);
766                 proxy_port = GetProxyPort(lnk);
767
768                 /* Walk out chain. */           
769                 error = find_handler(IN, UDP, la, pip, &ad);
770                 /* If we cannot figure out the packet, ignore it. */
771                 if (error < 0)
772                         return (PKT_ALIAS_IGNORED);
773
774 /* If UDP checksum is not zero, then adjust since destination port */
775 /* is being unaliased and destination address is being altered.    */
776                 if (ud->uh_sum != 0) {
777                         accumulate = alias_port;
778                         accumulate -= ud->uh_dport;
779                         accumulate += twowords(&alias_address);
780                         accumulate -= twowords(&original_address);
781
782 /* If this is a proxy packet, modify checksum because of source change.*/
783                         if (proxy_port != 0) {
784                                 accumulate += ud->uh_sport;
785                                 accumulate -= proxy_port;
786                         }
787
788                         if (proxy_address.s_addr != 0) {
789                                 accumulate += twowords(&pip->ip_src);
790                                 accumulate -= twowords(&proxy_address);
791                         }
792
793                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
794                 }
795 /* XXX: Could the two if's below be concatenated to one ? */
796 /* Restore source port and/or address in case of proxying*/
797
798                 if (proxy_port != 0)
799                         ud->uh_sport = proxy_port;
800
801                 if (proxy_address.s_addr != 0) {
802                         DifferentialChecksum(&pip->ip_sum,
803                             &proxy_address, &pip->ip_src, 2);
804                         pip->ip_src = proxy_address;
805                 }
806
807 /* Restore original IP address */
808                 DifferentialChecksum(&pip->ip_sum,
809                     &original_address, &pip->ip_dst, 2);
810                 pip->ip_dst = original_address;
811
812                 return (PKT_ALIAS_OK);
813         }
814         return (PKT_ALIAS_IGNORED);
815 }
816
817 static int
818 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
819 {
820         struct udphdr *ud;
821         struct alias_link *lnk;
822         struct in_addr dest_address;
823         struct in_addr proxy_server_address;
824         u_short dest_port;
825         u_short proxy_server_port;
826         int proxy_type;
827         int error;
828
829         LIBALIAS_LOCK_ASSERT(la);
830
831 /* Return if proxy-only mode is enabled and not proxyrule found.*/
832         ud = (struct udphdr *)ip_next(pip);
833         proxy_type = ProxyCheck(la, &proxy_server_address, 
834                 &proxy_server_port, pip->ip_src, pip->ip_dst, 
835                 ud->uh_dport, pip->ip_p);
836         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
837                 return (PKT_ALIAS_OK);
838
839 /* If this is a transparent proxy, save original destination,
840  * then alter the destination and adjust checksums */
841         dest_port = ud->uh_dport;
842         dest_address = pip->ip_dst;
843
844         if (proxy_type != 0) {
845                 int accumulate;
846
847                 accumulate = twowords(&pip->ip_dst);
848                 accumulate -= twowords(&proxy_server_address);
849
850                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
851
852                 if (ud->uh_sum != 0) {
853                         accumulate = twowords(&pip->ip_dst);
854                         accumulate -= twowords(&proxy_server_address);
855                         accumulate += ud->uh_dport;
856                         accumulate -= proxy_server_port;
857                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
858                 }
859                 pip->ip_dst = proxy_server_address;
860                 ud->uh_dport = proxy_server_port;
861         }
862         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
863             ud->uh_sport, ud->uh_dport,
864             IPPROTO_UDP, create);
865         if (lnk != NULL) {
866                 u_short alias_port;
867                 struct in_addr alias_address;
868                 struct alias_data ad = {
869                         .lnk = lnk, 
870                         .oaddr = NULL,
871                         .aaddr = &alias_address,
872                         .aport = &alias_port,
873                         .sport = &ud->uh_sport,
874                         .dport = &ud->uh_dport,
875                         .maxpktsize = 0
876                 };
877
878 /* Save original destination address, if this is a proxy packet.
879  * Also modify packet to include destination encoding.  This may
880  * change the size of IP header. */
881                 if (proxy_type != 0) {
882                         SetProxyPort(lnk, dest_port);
883                         SetProxyAddress(lnk, dest_address);
884                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
885                         ud = (struct udphdr *)ip_next(pip);
886                 }
887
888                 alias_address = GetAliasAddress(lnk);
889                 alias_port = GetAliasPort(lnk);
890
891                 /* Walk out chain. */           
892                 error = find_handler(OUT, UDP, la, pip, &ad);
893
894 /* If UDP checksum is not zero, adjust since source port is */
895 /* being aliased and source address is being altered        */
896                 if (ud->uh_sum != 0) {
897                         int accumulate;
898
899                         accumulate = ud->uh_sport;
900                         accumulate -= alias_port;
901                         accumulate += twowords(&pip->ip_src);
902                         accumulate -= twowords(&alias_address);
903                         ADJUST_CHECKSUM(accumulate, ud->uh_sum);
904                 }
905 /* Put alias port in UDP header */
906                 ud->uh_sport = alias_port;
907
908 /* Change source address */
909                 DifferentialChecksum(&pip->ip_sum,
910                     &alias_address, &pip->ip_src, 2);
911                 pip->ip_src = alias_address;
912
913                 return (PKT_ALIAS_OK);
914         }
915         return (PKT_ALIAS_IGNORED);
916 }
917
918
919
920 static int
921 TcpAliasIn(struct libalias *la, struct ip *pip)
922 {
923         struct tcphdr *tc;
924         struct alias_link *lnk;
925
926         LIBALIAS_LOCK_ASSERT(la);
927         tc = (struct tcphdr *)ip_next(pip);
928
929         lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
930             tc->th_sport, tc->th_dport,
931             IPPROTO_TCP,
932             !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
933         if (lnk != NULL) {
934                 struct in_addr alias_address;
935                 struct in_addr original_address;
936                 struct in_addr proxy_address;
937                 u_short alias_port;
938                 u_short proxy_port;
939                 int accumulate, error;
940
941                 /* 
942                  * The init of MANY vars is a bit below, but aliashandlepptpin 
943                  * seems to need the destination port that came within the
944                  * packet and not the original one looks below [*].
945                  */
946
947                 struct alias_data ad = {
948                         .lnk = lnk, 
949                         .oaddr = NULL,
950                         .aaddr = NULL,
951                         .aport = NULL,
952                         .sport = &tc->th_sport,
953                         .dport = &tc->th_dport,
954                         .maxpktsize = 0
955                 };
956
957                 /* Walk out chain. */           
958                 error = find_handler(IN, TCP, la, pip, &ad);
959
960                 alias_address = GetAliasAddress(lnk);
961                 original_address = GetOriginalAddress(lnk);
962                 proxy_address = GetProxyAddress(lnk);
963                 alias_port = tc->th_dport;
964                 tc->th_dport = GetOriginalPort(lnk);
965                 proxy_port = GetProxyPort(lnk);
966
967                 /* 
968                  * Look above, if anyone is going to add find_handler AFTER 
969                  * this aliashandlepptpin/point, please redo alias_data too.
970                  * Uncommenting the piece here below should be enough.
971                  */
972 #if 0
973                                  struct alias_data ad = {
974                                         .lnk = lnk,
975                                         .oaddr = &original_address,
976                                         .aaddr = &alias_address,
977                                         .aport = &alias_port,
978                                         .sport = &ud->uh_sport,
979                                         .dport = &ud->uh_dport,
980                                         .maxpktsize = 0
981                                 };
982                 
983                                 /* Walk out chain. */
984                                 error = find_handler(la, pip, &ad);
985                                 if (error == EHDNOF)
986                                         printf("Protocol handler not found\n");
987 #endif
988
989 /* Adjust TCP checksum since destination port is being unaliased */
990 /* and destination port is being altered.                        */
991                 accumulate = alias_port;
992                 accumulate -= tc->th_dport;
993                 accumulate += twowords(&alias_address);
994                 accumulate -= twowords(&original_address);
995
996 /* If this is a proxy, then modify the TCP source port and
997    checksum accumulation */
998                 if (proxy_port != 0) {
999                         accumulate += tc->th_sport;
1000                         tc->th_sport = proxy_port;
1001                         accumulate -= tc->th_sport;
1002                         accumulate += twowords(&pip->ip_src);
1003                         accumulate -= twowords(&proxy_address);
1004                 }
1005 /* See if ACK number needs to be modified */
1006                 if (GetAckModified(lnk) == 1) {
1007                         int delta;
1008
1009                         tc = (struct tcphdr *)ip_next(pip);
1010                         delta = GetDeltaAckIn(tc->th_ack, lnk);
1011                         if (delta != 0) {
1012                                 accumulate += twowords(&tc->th_ack);
1013                                 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1014                                 accumulate -= twowords(&tc->th_ack);
1015                         }
1016                 }
1017                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1018
1019 /* Restore original IP address */
1020                 accumulate = twowords(&pip->ip_dst);
1021                 pip->ip_dst = original_address;
1022                 accumulate -= twowords(&pip->ip_dst);
1023
1024 /* If this is a transparent proxy packet, then modify the source
1025    address */
1026                 if (proxy_address.s_addr != 0) {
1027                         accumulate += twowords(&pip->ip_src);
1028                         pip->ip_src = proxy_address;
1029                         accumulate -= twowords(&pip->ip_src);
1030                 }
1031                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1032
1033 /* Monitor TCP connection state */
1034                 tc = (struct tcphdr *)ip_next(pip);
1035                 TcpMonitorIn(tc->th_flags, lnk);
1036
1037                 return (PKT_ALIAS_OK);
1038         }
1039         return (PKT_ALIAS_IGNORED);
1040 }
1041
1042 static int
1043 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1044 {
1045         int proxy_type, error;
1046         u_short dest_port;
1047         u_short proxy_server_port;
1048         struct in_addr dest_address;
1049         struct in_addr proxy_server_address;
1050         struct tcphdr *tc;
1051         struct alias_link *lnk;
1052
1053         LIBALIAS_LOCK_ASSERT(la);
1054         tc = (struct tcphdr *)ip_next(pip);
1055
1056         if (create)
1057                 proxy_type = ProxyCheck(la, &proxy_server_address, 
1058                     &proxy_server_port, pip->ip_src, pip->ip_dst, 
1059                     tc->th_dport, pip->ip_p);
1060         else
1061                 proxy_type = 0;
1062
1063         if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1064                 return (PKT_ALIAS_OK);
1065
1066 /* If this is a transparent proxy, save original destination,
1067    then alter the destination and adjust checksums */
1068         dest_port = tc->th_dport;
1069         dest_address = pip->ip_dst;
1070         if (proxy_type != 0) {
1071                 int accumulate;
1072
1073                 accumulate = tc->th_dport;
1074                 tc->th_dport = proxy_server_port;
1075                 accumulate -= tc->th_dport;
1076                 accumulate += twowords(&pip->ip_dst);
1077                 accumulate -= twowords(&proxy_server_address);
1078                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1079
1080                 accumulate = twowords(&pip->ip_dst);
1081                 pip->ip_dst = proxy_server_address;
1082                 accumulate -= twowords(&pip->ip_dst);
1083                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1084         }
1085         lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1086             tc->th_sport, tc->th_dport,
1087             IPPROTO_TCP, create);
1088         if (lnk == NULL)
1089                 return (PKT_ALIAS_IGNORED);
1090         if (lnk != NULL) {
1091                 u_short alias_port;
1092                 struct in_addr alias_address;
1093                 int accumulate;
1094                 struct alias_data ad = {
1095                         .lnk = lnk, 
1096                         .oaddr = NULL,
1097                         .aaddr = &alias_address,
1098                         .aport = &alias_port,
1099                         .sport = &tc->th_sport,
1100                         .dport = &tc->th_dport,
1101                         .maxpktsize = maxpacketsize
1102                 };
1103
1104 /* Save original destination address, if this is a proxy packet.
1105    Also modify packet to include destination encoding.  This may
1106    change the size of IP header. */
1107                 if (proxy_type != 0) {
1108                         SetProxyPort(lnk, dest_port);
1109                         SetProxyAddress(lnk, dest_address);
1110                         ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1111                         tc = (struct tcphdr *)ip_next(pip);
1112                 }
1113 /* Get alias address and port */
1114                 alias_port = GetAliasPort(lnk);
1115                 alias_address = GetAliasAddress(lnk);
1116
1117 /* Monitor TCP connection state */
1118                 tc = (struct tcphdr *)ip_next(pip);
1119                 TcpMonitorOut(tc->th_flags, lnk);
1120                 
1121                 /* Walk out chain. */           
1122                 error = find_handler(OUT, TCP, la, pip, &ad);
1123
1124 /* Adjust TCP checksum since source port is being aliased */
1125 /* and source address is being altered                    */
1126                 accumulate = tc->th_sport;
1127                 tc->th_sport = alias_port;
1128                 accumulate -= tc->th_sport;
1129                 accumulate += twowords(&pip->ip_src);
1130                 accumulate -= twowords(&alias_address);
1131
1132 /* Modify sequence number if necessary */
1133                 if (GetAckModified(lnk) == 1) {
1134                         int delta;
1135                         
1136                         tc = (struct tcphdr *)ip_next(pip);
1137                         delta = GetDeltaSeqOut(tc->th_seq, lnk);
1138                         if (delta != 0) {
1139                                 accumulate += twowords(&tc->th_seq);
1140                                 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1141                                 accumulate -= twowords(&tc->th_seq);
1142                         }
1143                 }
1144                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1145
1146 /* Change source address */
1147                 accumulate = twowords(&pip->ip_src);
1148                 pip->ip_src = alias_address;
1149                 accumulate -= twowords(&pip->ip_src);
1150                 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1151
1152                 return (PKT_ALIAS_OK);
1153         }
1154         return (PKT_ALIAS_IGNORED);
1155 }
1156
1157
1158
1159
1160 /* Fragment Handling
1161
1162     FragmentIn()
1163     FragmentOut()
1164
1165 The packet aliasing module has a limited ability for handling IP
1166 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1167 received, then the ID number of the IP packet is saved, and other
1168 fragments are identified according to their ID number and IP address
1169 they were sent from.  Pointers to unresolved fragments can also be
1170 saved and recalled when a header fragment is seen.
1171 */
1172
1173 /* Local prototypes */
1174 static int      FragmentIn(struct libalias *la, struct in_addr ip_src, 
1175                     struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum);                
1176 static int      FragmentOut(struct libalias *, struct in_addr *ip_src, 
1177                     u_short *ip_sum);
1178
1179 static int
1180 FragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst,
1181     u_short ip_id, u_short *ip_sum)
1182 {
1183         struct alias_link *lnk;
1184
1185         LIBALIAS_LOCK_ASSERT(la);
1186         lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id);
1187         if (lnk != NULL) {
1188                 struct in_addr original_address;
1189
1190                 GetFragmentAddr(lnk, &original_address);
1191                 DifferentialChecksum(ip_sum,
1192                     &original_address, ip_dst, 2);
1193                 *ip_dst = original_address;
1194
1195                 return (PKT_ALIAS_OK);
1196         }
1197         return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1198 }
1199
1200 static int
1201 FragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum)
1202 {
1203         struct in_addr alias_address;
1204
1205         LIBALIAS_LOCK_ASSERT(la);
1206         alias_address = FindAliasAddress(la, *ip_src);
1207         DifferentialChecksum(ip_sum,
1208             &alias_address, ip_src, 2);
1209         *ip_src = alias_address;
1210
1211         return (PKT_ALIAS_OK);
1212 }
1213
1214
1215
1216
1217
1218
1219 /* Outside World Access
1220
1221         PacketAliasSaveFragment()
1222         PacketAliasGetFragment()
1223         PacketAliasFragmentIn()
1224         PacketAliasIn()
1225         PacketAliasOut()
1226         PacketUnaliasOut()
1227
1228 (prototypes in alias.h)
1229 */
1230
1231 int
1232 LibAliasSaveFragment(struct libalias *la, char *ptr)
1233 {
1234         int iresult;
1235         struct alias_link *lnk;
1236         struct ip *pip;
1237
1238         LIBALIAS_LOCK(la);
1239         pip = (struct ip *)ptr;
1240         lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1241         iresult = PKT_ALIAS_ERROR;
1242         if (lnk != NULL) {
1243                 SetFragmentPtr(lnk, ptr);
1244                 iresult = PKT_ALIAS_OK;
1245         }
1246         LIBALIAS_UNLOCK(la);
1247         return (iresult);
1248 }
1249
1250 char           *
1251 LibAliasGetFragment(struct libalias *la, char *ptr)
1252 {
1253         struct alias_link *lnk;
1254         char *fptr;
1255         struct ip *pip;
1256
1257         LIBALIAS_LOCK(la);
1258         pip = (struct ip *)ptr;
1259         lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1260         if (lnk != NULL) {
1261                 GetFragmentPtr(lnk, &fptr);
1262                 SetFragmentPtr(lnk, NULL);
1263                 SetExpire(lnk, 0);      /* Deletes link */
1264         } else          
1265                 fptr = NULL;
1266
1267         LIBALIAS_UNLOCK(la);
1268         return (fptr);
1269 }
1270
1271 void
1272 LibAliasFragmentIn(struct libalias *la, char *ptr,      /* Points to correctly
1273                                                          * de-aliased header
1274                                                          * fragment */
1275     char *ptr_fragment          /* Points to fragment which must be
1276                                  * de-aliased   */
1277 )
1278 {
1279         struct ip *pip;
1280         struct ip *fpip;
1281
1282         LIBALIAS_LOCK(la);
1283         (void)la;
1284         pip = (struct ip *)ptr;
1285         fpip = (struct ip *)ptr_fragment;
1286
1287         DifferentialChecksum(&fpip->ip_sum,
1288             &pip->ip_dst, &fpip->ip_dst, 2);
1289         fpip->ip_dst = pip->ip_dst;
1290         LIBALIAS_UNLOCK(la);
1291 }
1292
1293 /* Local prototypes */
1294 static int
1295 LibAliasOutLocked(struct libalias *la, char *ptr,
1296                   int maxpacketsize, int create);
1297 static int
1298 LibAliasInLocked(struct libalias *la, char *ptr,
1299                   int maxpacketsize);
1300
1301 int
1302 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1303 {
1304         int res;
1305
1306         LIBALIAS_LOCK(la);
1307         res = LibAliasInLocked(la, ptr, maxpacketsize);
1308         LIBALIAS_UNLOCK(la);
1309         return (res);
1310 }
1311
1312 static int
1313 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1314 {
1315         struct in_addr alias_addr;
1316         struct ip *pip;
1317         int iresult;
1318
1319         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1320                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1321                 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1322                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1323                 goto getout;
1324         }
1325         HouseKeeping(la);
1326         ClearCheckNewLink(la);
1327         pip = (struct ip *)ptr;
1328         alias_addr = pip->ip_dst;
1329
1330         /* Defense against mangled packets */
1331         if (ntohs(pip->ip_len) > maxpacketsize
1332             || (pip->ip_hl << 2) > maxpacketsize) {
1333                 iresult = PKT_ALIAS_IGNORED; 
1334                 goto getout;
1335         }
1336
1337         iresult = PKT_ALIAS_IGNORED;
1338         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1339                 switch (pip->ip_p) {
1340                 case IPPROTO_ICMP:
1341                         iresult = IcmpAliasIn(la, pip);
1342                         break;
1343                 case IPPROTO_UDP:
1344                         iresult = UdpAliasIn(la, pip);
1345                         break;
1346                 case IPPROTO_TCP:
1347                         iresult = TcpAliasIn(la, pip);
1348                         break;
1349 #ifdef _KERNEL
1350                 case IPPROTO_SCTP:
1351                   iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1352                         break;
1353 #endif
1354                 case IPPROTO_GRE: {
1355                         int error;
1356                         struct alias_data ad = {
1357                                 .lnk = NULL, 
1358                                 .oaddr = NULL, 
1359                                 .aaddr = NULL,
1360                                 .aport = NULL,
1361                                 .sport = NULL,
1362                                 .dport = NULL,
1363                                 .maxpktsize = 0                  
1364                         };
1365                         
1366                         /* Walk out chain. */           
1367                         error = find_handler(IN, IP, la, pip, &ad);
1368                         if (error ==  0)
1369                                 iresult = PKT_ALIAS_OK;
1370                         else
1371                                 iresult = ProtoAliasIn(la, pip->ip_src, 
1372                                     &pip->ip_dst, pip->ip_p, &pip->ip_sum);
1373                 }
1374                         break; 
1375                 default:
1376                         iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst,
1377                             pip->ip_p, &pip->ip_sum);
1378                         break;
1379                 }
1380
1381                 if (ntohs(pip->ip_off) & IP_MF) {
1382                         struct alias_link *lnk;
1383
1384                         lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1385                         if (lnk != NULL) {
1386                                 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1387                                 SetFragmentAddr(lnk, pip->ip_dst);
1388                         } else {
1389                                 iresult = PKT_ALIAS_ERROR;
1390                         }
1391                 }
1392         } else {
1393                 iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id,
1394                     &pip->ip_sum);
1395         }
1396
1397 getout:
1398         return (iresult);
1399 }
1400
1401
1402
1403 /* Unregistered address ranges */
1404
1405 /* 10.0.0.0   ->   10.255.255.255 */
1406 #define UNREG_ADDR_A_LOWER 0x0a000000
1407 #define UNREG_ADDR_A_UPPER 0x0affffff
1408
1409 /* 172.16.0.0  ->  172.31.255.255 */
1410 #define UNREG_ADDR_B_LOWER 0xac100000
1411 #define UNREG_ADDR_B_UPPER 0xac1fffff
1412
1413 /* 192.168.0.0 -> 192.168.255.255 */
1414 #define UNREG_ADDR_C_LOWER 0xc0a80000
1415 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1416
1417 /* 100.64.0.0  -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
1418 #define UNREG_ADDR_CGN_LOWER 0x64400000
1419 #define UNREG_ADDR_CGN_UPPER 0x647fffff
1420
1421 int
1422 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1423 {
1424         int res;
1425
1426         LIBALIAS_LOCK(la);
1427         res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1428         LIBALIAS_UNLOCK(la);
1429         return (res);
1430 }
1431
1432 int
1433 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1434 {
1435         int res;
1436
1437         LIBALIAS_LOCK(la);
1438         res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1439         LIBALIAS_UNLOCK(la);
1440         return (res);
1441 }
1442
1443 static int
1444 LibAliasOutLocked(struct libalias *la, char *ptr,       /* valid IP packet */
1445     int maxpacketsize,          /* How much the packet data may grow (FTP
1446                                  * and IRC inline changes) */
1447     int create                  /* Create new entries ? */
1448 )
1449 {
1450         int iresult;
1451         struct in_addr addr_save;
1452         struct ip *pip;
1453
1454         if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1455                 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1456                 iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1457                 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1458                 goto getout;
1459         }
1460         HouseKeeping(la);
1461         ClearCheckNewLink(la);
1462         pip = (struct ip *)ptr;
1463
1464         /* Defense against mangled packets */
1465         if (ntohs(pip->ip_len) > maxpacketsize
1466             || (pip->ip_hl << 2) > maxpacketsize) {
1467                 iresult = PKT_ALIAS_IGNORED;
1468                 goto getout;
1469         }
1470
1471         addr_save = GetDefaultAliasAddress(la);
1472         if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
1473             la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1474                 u_long addr;
1475                 int iclass;
1476
1477                 iclass = 0;
1478                 addr = ntohl(pip->ip_src.s_addr);
1479                 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1480                         iclass = 3;
1481                 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1482                         iclass = 2;
1483                 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1484                         iclass = 1;
1485                 else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
1486                     la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
1487                         iclass = 4;
1488
1489                 if (iclass == 0) {
1490                         SetDefaultAliasAddress(la, pip->ip_src);
1491                 }
1492         } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1493                 SetDefaultAliasAddress(la, pip->ip_src);
1494         }
1495         iresult = PKT_ALIAS_IGNORED;
1496         if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1497                 switch (pip->ip_p) {
1498                 case IPPROTO_ICMP:
1499                         iresult = IcmpAliasOut(la, pip, create);
1500                         break;
1501                 case IPPROTO_UDP:
1502                         iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1503                         break;
1504                 case IPPROTO_TCP:
1505                         iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1506                         break;
1507 #ifdef _KERNEL
1508                 case IPPROTO_SCTP:
1509                   iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1510                         break;
1511 #endif
1512                 case IPPROTO_GRE: {
1513                         int error;
1514                         struct alias_data ad = {
1515                                 .lnk = NULL, 
1516                                 .oaddr = NULL, 
1517                                 .aaddr = NULL,
1518                                 .aport = NULL,
1519                                 .sport = NULL,
1520                                 .dport = NULL,
1521                                 .maxpktsize = 0                  
1522                         };
1523                         /* Walk out chain. */           
1524                         error = find_handler(OUT, IP, la, pip, &ad);
1525                         if (error == 0)
1526                                 iresult = PKT_ALIAS_OK;
1527                         else
1528                                 iresult = ProtoAliasOut(la, &pip->ip_src, 
1529                                     pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1530                 }
1531                         break;
1532                 default:
1533                         iresult = ProtoAliasOut(la, &pip->ip_src,
1534                             pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1535                         break;
1536                 }
1537         } else {
1538                 iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum);
1539         }
1540
1541         SetDefaultAliasAddress(la, addr_save);
1542 getout:
1543         return (iresult);
1544 }
1545
1546 int
1547 LibAliasUnaliasOut(struct libalias *la, char *ptr,      /* valid IP packet */
1548     int maxpacketsize           /* for error checking */
1549 )
1550 {
1551         struct ip *pip;
1552         struct icmp *ic;
1553         struct udphdr *ud;
1554         struct tcphdr *tc;
1555         struct alias_link *lnk;
1556         int iresult = PKT_ALIAS_IGNORED;
1557
1558         LIBALIAS_LOCK(la);
1559         pip = (struct ip *)ptr;
1560
1561         /* Defense against mangled packets */
1562         if (ntohs(pip->ip_len) > maxpacketsize
1563             || (pip->ip_hl << 2) > maxpacketsize)
1564                 goto getout;
1565
1566         ud = (struct udphdr *)ip_next(pip);
1567         tc = (struct tcphdr *)ip_next(pip);
1568         ic = (struct icmp *)ip_next(pip);
1569
1570         /* Find a link */
1571         if (pip->ip_p == IPPROTO_UDP)
1572                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1573                     ud->uh_dport, ud->uh_sport,
1574                     IPPROTO_UDP, 0);
1575         else if (pip->ip_p == IPPROTO_TCP)
1576                 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1577                     tc->th_dport, tc->th_sport,
1578                     IPPROTO_TCP, 0);
1579         else if (pip->ip_p == IPPROTO_ICMP)
1580                 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1581         else
1582                 lnk = NULL;
1583
1584         /* Change it from an aliased packet to an unaliased packet */
1585         if (lnk != NULL) {
1586                 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1587                         int accumulate;
1588                         struct in_addr original_address;
1589                         u_short original_port;
1590
1591                         original_address = GetOriginalAddress(lnk);
1592                         original_port = GetOriginalPort(lnk);
1593
1594                         /* Adjust TCP/UDP checksum */
1595                         accumulate = twowords(&pip->ip_src);
1596                         accumulate -= twowords(&original_address);
1597
1598                         if (pip->ip_p == IPPROTO_UDP) {
1599                                 accumulate += ud->uh_sport;
1600                                 accumulate -= original_port;
1601                                 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1602                         } else {
1603                                 accumulate += tc->th_sport;
1604                                 accumulate -= original_port;
1605                                 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1606                         }
1607
1608                         /* Adjust IP checksum */
1609                         DifferentialChecksum(&pip->ip_sum,
1610                             &original_address, &pip->ip_src, 2);
1611
1612                         /* Un-alias source address and port number */
1613                         pip->ip_src = original_address;
1614                         if (pip->ip_p == IPPROTO_UDP)
1615                                 ud->uh_sport = original_port;
1616                         else
1617                                 tc->th_sport = original_port;
1618
1619                         iresult = PKT_ALIAS_OK;
1620
1621                 } else if (pip->ip_p == IPPROTO_ICMP) {
1622
1623                         int accumulate;
1624                         struct in_addr original_address;
1625                         u_short original_id;
1626
1627                         original_address = GetOriginalAddress(lnk);
1628                         original_id = GetOriginalPort(lnk);
1629
1630                         /* Adjust ICMP checksum */
1631                         accumulate = twowords(&pip->ip_src);
1632                         accumulate -= twowords(&original_address);
1633                         accumulate += ic->icmp_id;
1634                         accumulate -= original_id;
1635                         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1636
1637                         /* Adjust IP checksum */
1638                         DifferentialChecksum(&pip->ip_sum,
1639                             &original_address, &pip->ip_src, 2);
1640
1641                         /* Un-alias source address and port number */
1642                         pip->ip_src = original_address;
1643                         ic->icmp_id = original_id;
1644
1645                         iresult = PKT_ALIAS_OK;
1646                 }
1647         }
1648 getout:
1649         LIBALIAS_UNLOCK(la);
1650         return (iresult);
1651
1652 }
1653
1654 #ifndef _KERNEL
1655
1656 int
1657 LibAliasRefreshModules(void)
1658 {
1659         char buf[256], conf[] = "/etc/libalias.conf";
1660         FILE *fd;
1661         int i, len;
1662
1663         fd = fopen(conf, "r");
1664         if (fd == NULL)
1665                 err(1, "fopen(%s)", conf);
1666
1667         LibAliasUnLoadAllModule();
1668
1669         for (;;) {
1670                 fgets(buf, 256, fd);
1671                 if (feof(fd)) 
1672                         break;
1673                 len = strlen(buf);
1674                 if (len > 1) {
1675                         for (i = 0; i < len; i++)
1676                                 if (!isspace(buf[i]))
1677                                         break;
1678                         if (buf[i] == '#')
1679                                 continue;
1680                         buf[len - 1] = '\0';
1681                         LibAliasLoadModule(buf);
1682                 }
1683         }
1684         fclose(fd);
1685         return (0);
1686 }
1687
1688 int
1689 LibAliasLoadModule(char *path)
1690 {
1691         struct dll *t;
1692         void *handle;
1693         struct proto_handler *m;
1694         const char *error;
1695         moduledata_t *p;
1696
1697         handle = dlopen (path, RTLD_LAZY);
1698         if (!handle) {
1699                 fprintf(stderr, "%s\n", dlerror());
1700                 return (EINVAL);
1701         }
1702
1703         p = dlsym(handle, "alias_mod");
1704         if ((error = dlerror()) != NULL)  {
1705                 fprintf(stderr, "%s\n", dlerror());
1706                 return (EINVAL);
1707         }
1708
1709         t = malloc(sizeof(struct dll));
1710         if (t == NULL)
1711                 return (ENOMEM);
1712         strncpy(t->name, p->name, DLL_LEN);
1713         t->handle = handle;
1714         if (attach_dll(t) == EEXIST) {
1715                 free(t);
1716                 fprintf(stderr, "dll conflict\n");
1717                 return (EEXIST);
1718         }
1719
1720         m = dlsym(t->handle, "handlers");
1721         if ((error = dlerror()) != NULL)  {
1722                 fprintf(stderr, "%s\n", error);
1723                 return (EINVAL);
1724         }
1725
1726         LibAliasAttachHandlers(m);
1727         return (0);
1728 }
1729
1730 int
1731 LibAliasUnLoadAllModule(void)
1732 {
1733         struct dll *t;
1734         struct proto_handler *p;
1735
1736         /* Unload all modules then reload everything. */
1737         while ((p = first_handler()) != NULL) { 
1738                 LibAliasDetachHandlers(p);
1739         }
1740         while ((t = walk_dll_chain()) != NULL) {        
1741                 dlclose(t->handle);
1742                 free(t);
1743         }
1744         return (1);
1745 }
1746
1747 #endif
1748
1749 #ifdef _KERNEL
1750 /*
1751  * m_megapullup() - this function is a big hack.
1752  * Thankfully, it's only used in ng_nat and ipfw+nat.
1753  *
1754  * It allocates an mbuf with cluster and copies the specified part of the chain
1755  * into cluster, so that it is all contiguous and can be accessed via a plain
1756  * (char *) pointer. This is required, because libalias doesn't know how to
1757  * handle mbuf chains.
1758  *
1759  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1760  * the input packet, on failure NULL. The input packet is always consumed.
1761  */
1762 struct mbuf *
1763 m_megapullup(struct mbuf *m, int len)
1764 {
1765         struct mbuf *mcl;
1766
1767         if (len > m->m_pkthdr.len)
1768                 goto bad;
1769
1770         if (m->m_next == NULL && M_WRITABLE(m))
1771                 return (m);
1772
1773         if (len <= MJUMPAGESIZE)
1774                 mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1775         else if (len <= MJUM9BYTES)
1776                 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1777         else if (len <= MJUM16BYTES)
1778                 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1779         else
1780                 goto bad;
1781         if (mcl == NULL)
1782                 goto bad;
1783         m_align(mcl, len);
1784         m_move_pkthdr(mcl, m);
1785         m_copydata(m, 0, len, mtod(mcl, caddr_t));
1786         mcl->m_len = mcl->m_pkthdr.len = len;
1787         m_freem(m);
1788
1789         return (mcl);
1790 bad:
1791         m_freem(m);
1792         return (NULL);
1793 }
1794 #endif