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