xref: /freebsd/sys/netinet/libalias/alias.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
1 /* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
2 /*
3     Alias.c provides supervisory control for the functions of the
4     packet aliasing software.  It consists of routines to monitor
5     TCP connection state, protocol-specific aliasing routines,
6     fragment handling and the following outside world functional
7     interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
8     PacketAliasIn and PacketAliasOut.
9 
10     The other C program files are briefly described. The data
11     structure framework which holds information needed to translate
12     packets is encapsulated in alias_db.c.  Data is accessed by
13     function calls, so other segments of the program need not know
14     about the underlying data structures.  Alias_ftp.c contains
15     special code for modifying the ftp PORT command used to establish
16     data connections, while alias_irc.c do the same for IRC
17     DCC. Alias_util.c contains a few utility routines.
18 
19     This software is placed into the public domain with no restrictions
20     on its distribution.
21 
22     Version 1.0 August, 1996  (cjm)
23 
24     Version 1.1 August 20, 1996  (cjm)
25         PPP host accepts incoming connections for ports 0 to 1023.
26         (Gary Roberts pointed out the need to handle incoming
27          connections.)
28 
29     Version 1.2 September 7, 1996 (cjm)
30         Fragment handling error in alias_db.c corrected.
31         (Tom Torrance helped fix this problem.)
32 
33     Version 1.4 September 16, 1996 (cjm)
34         - A more generalized method for handling incoming
35           connections, without the 0-1023 restriction, is
36           implemented in alias_db.c
37         - Improved ICMP support in alias.c.  Traceroute
38           packet streams can now be correctly aliased.
39         - TCP connection closing logic simplified in
40           alias.c and now allows for additional 1 minute
41           "grace period" after FIN or RST is observed.
42 
43     Version 1.5 September 17, 1996 (cjm)
44         Corrected error in handling incoming UDP packets with 0 checksum.
45         (Tom Torrance helped fix this problem.)
46 
47     Version 1.6 September 18, 1996 (cjm)
48         Simplified ICMP aliasing scheme.  Should now support
49         traceroute from Win95 as well as FreeBSD.
50 
51     Version 1.7 January 9, 1997 (cjm)
52         - Out-of-order fragment handling.
53         - IP checksum error fixed for ftp transfers
54           from aliasing host.
55         - Integer return codes added to all
56           aliasing/de-aliasing functions.
57         - Some obsolete comments cleaned up.
58         - Differential checksum computations for
59           IP header (TCP, UDP and ICMP were already
60           differential).
61 
62     Version 2.1 May 1997 (cjm)
63         - Added support for outgoing ICMP error
64           messages.
65         - Added two functions PacketAliasIn2()
66           and PacketAliasOut2() for dynamic address
67           control (e.g. round-robin allocation of
68           incoming packets).
69 
70     Version 2.2 July 1997 (cjm)
71         - Rationalized API function names to begin
72           with "PacketAlias..."
73         - Eliminated PacketAliasIn2() and
74           PacketAliasOut2() as poorly conceived.
75 
76     See HISTORY file for additional revisions.
77 
78 */
79 
80 #include <stdio.h>
81 #include <unistd.h>
82 
83 #include <sys/param.h>
84 #include <sys/types.h>
85 
86 #include <netinet/in_systm.h>
87 #include <netinet/in.h>
88 #include <netinet/ip.h>
89 #include <netinet/ip_icmp.h>
90 #include <netinet/tcp.h>
91 #include <netinet/udp.h>
92 
93 #include "alias_local.h"
94 #include "alias.h"
95 
96 #define NETBIOS_NS_PORT_NUMBER 137
97 #define NETBIOS_DGM_PORT_NUMBER 138
98 #define FTP_CONTROL_PORT_NUMBER 21
99 #define FTP_CONTROL_PORT_NUMBER 21
100 #define IRC_CONTROL_PORT_NUMBER_1 6667
101 #define IRC_CONTROL_PORT_NUMBER_2 6668
102 #define CUSEEME_PORT_NUMBER 7648
103 
104 /*
105    The following macro is used to update an
106    internet checksum.  "delta" is a 32-bit
107    accumulation of all the changes to the
108    checksum (adding in new 16-bit words and
109    subtracting out old words), and "cksum"
110    is the checksum value to be updated.
111 */
112 #define ADJUST_CHECKSUM(acc, cksum) { \
113     acc += cksum; \
114     if (acc < 0) \
115     { \
116         acc = -acc; \
117         acc = (acc >> 16) + (acc & 0xffff); \
118         acc += acc >> 16; \
119         cksum = (u_short) ~acc; \
120     } \
121     else \
122     { \
123         acc = (acc >> 16) + (acc & 0xffff); \
124         acc += acc >> 16; \
125         cksum = (u_short) acc; \
126     } \
127 }
128 
129 
130 
131 
132 /* TCP Handling Routines
133 
134     TcpMonitorIn()  -- These routines monitor TCP connections, and
135     TcpMonitorOut() -- delete a link node when a connection is closed.
136 
137 These routines look for SYN, ACK and RST flags to determine when TCP
138 connections open and close.  When a TCP connection closes, the data
139 structure containing packet aliasing information is deleted after
140 a timeout period.
141 */
142 
143 /* Local prototypes */
144 static void TcpMonitorIn(struct ip *, struct alias_link *);
145 
146 static void TcpMonitorOut(struct ip *, struct alias_link *);
147 
148 
149 static void
150 TcpMonitorIn(struct ip *pip, struct alias_link *link)
151 {
152     struct tcphdr *tc;
153 
154     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
155 
156     switch (GetStateIn(link))
157     {
158         case ALIAS_TCP_STATE_NOT_CONNECTED:
159             if (tc->th_flags & TH_SYN)
160                 SetStateIn(link, ALIAS_TCP_STATE_CONNECTED);
161             break;
162         case ALIAS_TCP_STATE_CONNECTED:
163             if (tc->th_flags & TH_FIN
164                 || tc->th_flags & TH_RST)
165                 SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED);
166             break;
167     }
168 }
169 
170 static void
171 TcpMonitorOut(struct ip *pip, struct alias_link *link)
172 {
173     struct tcphdr *tc;
174 
175     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
176 
177     switch (GetStateOut(link))
178     {
179         case ALIAS_TCP_STATE_NOT_CONNECTED:
180             if (tc->th_flags & TH_SYN)
181                 SetStateOut(link, ALIAS_TCP_STATE_CONNECTED);
182             break;
183         case ALIAS_TCP_STATE_CONNECTED:
184             if (tc->th_flags & TH_FIN
185                 || tc->th_flags & TH_RST)
186                 SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED);
187             break;
188     }
189 }
190 
191 
192 
193 
194 
195 /* Protocol Specific Packet Aliasing Routines
196 
197     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3()
198     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3()
199     UdpAliasIn(), UdpAliasOut()
200     TcpAliasIn(), TcpAliasOut()
201 
202 These routines handle protocol specific details of packet aliasing.
203 One may observe a certain amount of repetitive arithmetic in these
204 functions, the purpose of which is to compute a revised checksum
205 without actually summing over the entire data packet, which could be
206 unnecessarily time consuming.
207 
208 The purpose of the packet aliasing routines is to replace the source
209 address of the outgoing packet and then correctly put it back for
210 any incoming packets.  For TCP and UDP, ports are also re-mapped.
211 
212 For ICMP echo/timestamp requests and replies, the following scheme
213 is used: the id number is replaced by an alias for the outgoing
214 packet.
215 
216 ICMP error messages are handled by looking at the IP fragment
217 in the data section of the message.
218 
219 For TCP and UDP protocols, a port number is chosen for an outgoing
220 packet, and then incoming packets are identified by IP address and
221 port numbers.  For TCP packets, there is additional logic in the event
222 that sequence and ack numbers have been altered (as is the case for
223 FTP data port commands).
224 
225 The port numbers used by the packet aliasing module are not true
226 ports in the Unix sense.  No sockets are actually bound to ports.
227 They are more correctly thought of as placeholders.
228 
229 All packets go through the aliasing mechanism, whether they come from
230 the gateway machine or other machines on a local area network.
231 */
232 
233 
234 /* Local prototypes */
235 static int IcmpAliasIn1(struct ip *);
236 static int IcmpAliasIn2(struct ip *);
237 static int IcmpAliasIn3(struct ip *);
238 static int IcmpAliasIn (struct ip *);
239 
240 static int IcmpAliasOut1(struct ip *);
241 static int IcmpAliasOut2(struct ip *);
242 static int IcmpAliasOut3(struct ip *);
243 static int IcmpAliasOut (struct ip *);
244 
245 static int UdpAliasOut(struct ip *);
246 static int UdpAliasIn (struct ip *);
247 
248 static int TcpAliasOut(struct ip *, int);
249 static int TcpAliasIn (struct ip *);
250 
251 
252 static int
253 IcmpAliasIn1(struct ip *pip)
254 {
255 /*
256     De-alias incoming echo and timestamp replies
257 */
258     struct alias_link *link;
259     struct icmp *ic;
260 
261     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
262 
263 /* Get source address from ICMP data field and restore original data */
264     link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id);
265     if (link != NULL)
266     {
267         u_short original_id;
268         int accumulate;
269 
270         original_id = GetOriginalPort(link);
271 
272 /* Adjust ICMP checksum */
273         accumulate  = ic->icmp_id;
274         accumulate -= original_id;
275         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
276 
277 /* Put original sequence number back in */
278         ic->icmp_id = original_id;
279 
280 /* Put original address back into IP header */
281         {
282             struct in_addr original_address;
283 
284             original_address = GetOriginalAddress(link);
285             DifferentialChecksum(&pip->ip_sum,
286                                  (u_short *) &original_address,
287                                  (u_short *) &pip->ip_dst,
288                                  2);
289             pip->ip_dst = original_address;
290         }
291 
292         return(PKT_ALIAS_OK);
293     }
294     return(PKT_ALIAS_IGNORED);
295 }
296 
297 static int
298 IcmpAliasIn2(struct ip *pip)
299 {
300 /*
301     Alias incoming ICMP error messages containing
302     IP header and first 64 bits of datagram.
303 */
304     struct ip *ip;
305     struct icmp *ic, *ic2;
306     struct udphdr *ud;
307     struct tcphdr *tc;
308     struct alias_link *link;
309 
310     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
311     ip = (struct ip *) ic->icmp_data;
312 
313     ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2));
314     tc = (struct tcphdr *) ud;
315     ic2 = (struct icmp *) ud;
316 
317     if (ip->ip_p == IPPROTO_UDP)
318         link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
319                             ud->uh_dport, ud->uh_sport,
320                             IPPROTO_UDP);
321     else if (ip->ip_p == IPPROTO_TCP)
322         link = FindUdpTcpIn(ip->ip_dst, ip->ip_src,
323                             tc->th_dport, tc->th_sport,
324                             IPPROTO_TCP);
325     else if (ip->ip_p == IPPROTO_ICMP) {
326         if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
327             link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id);
328          else
329             link = NULL;
330     } else
331         link = NULL;
332 
333     if (link != NULL)
334     {
335         if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP)
336         {
337             u_short *sptr;
338             int accumulate;
339             struct in_addr original_address;
340             u_short original_port;
341 
342             original_address = GetOriginalAddress(link);
343             original_port = GetOriginalPort(link);
344 
345 /* Adjust ICMP checksum */
346             sptr = (u_short *) &(ip->ip_src);
347             accumulate  = *sptr++;
348             accumulate += *sptr;
349             sptr = (u_short *) &original_address;
350             accumulate -= *sptr++;
351             accumulate -= *sptr;
352             accumulate += ud->uh_sport;
353             accumulate -= original_port;
354             ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
355 
356 /* Un-alias address in IP header */
357             DifferentialChecksum(&pip->ip_sum,
358                                  (u_short *) &original_address,
359                                  (u_short *) &pip->ip_dst,
360                                  2);
361             pip->ip_dst = original_address;
362 
363 /* Un-alias address and port number of original IP packet
364 fragment contained in ICMP data section */
365             ip->ip_src = original_address;
366             ud->uh_sport = original_port;
367         }
368         else if (pip->ip_p == IPPROTO_ICMP)
369         {
370             u_short *sptr;
371             int accumulate;
372             struct in_addr original_address;
373             u_short original_id;
374 
375             original_address = GetOriginalAddress(link);
376             original_id = GetOriginalPort(link);
377 
378 /* Adjust ICMP checksum */
379             sptr = (u_short *) &(ip->ip_src);
380             accumulate  = *sptr++;
381             accumulate += *sptr;
382             sptr = (u_short *) &original_address;
383             accumulate -= *sptr++;
384             accumulate -= *sptr;
385             accumulate += ic2->icmp_id;
386             accumulate -= original_id;
387             ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
388 
389 /* Un-alias address in IP header */
390             DifferentialChecksum(&pip->ip_sum,
391                                  (u_short *) &original_address,
392                                  (u_short *) &pip->ip_dst,
393                                  2);
394             pip->ip_dst = original_address;
395 
396 /* Un-alias address of original IP packet and seqence number of
397    embedded icmp datagram */
398             ip->ip_src = original_address;
399             ic2->icmp_id = original_id;
400         }
401         return(PKT_ALIAS_OK);
402     }
403     return(PKT_ALIAS_IGNORED);
404 }
405 
406 
407 static int
408 IcmpAliasIn3(struct ip *pip)
409 {
410     struct in_addr original_address;
411 
412     original_address = FindOriginalAddress(pip->ip_dst);
413     DifferentialChecksum(&pip->ip_sum,
414                          (u_short *) &original_address,
415                          (u_short *) &pip->ip_dst,
416                          2);
417     pip->ip_dst = original_address;
418 
419     return PKT_ALIAS_OK;
420 }
421 
422 
423 static int
424 IcmpAliasIn(struct ip *pip)
425 {
426     int iresult;
427     struct icmp *ic;
428 
429     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
430 
431     iresult = PKT_ALIAS_IGNORED;
432     switch (ic->icmp_type)
433     {
434         case ICMP_ECHOREPLY:
435         case ICMP_TSTAMPREPLY:
436             if (ic->icmp_code == 0)
437             {
438                 iresult = IcmpAliasIn1(pip);
439             }
440             break;
441         case ICMP_UNREACH:
442         case ICMP_SOURCEQUENCH:
443         case ICMP_TIMXCEED:
444         case ICMP_PARAMPROB:
445             iresult = IcmpAliasIn2(pip);
446             break;
447         case ICMP_ECHO:
448         case ICMP_TSTAMP:
449             iresult = IcmpAliasIn3(pip);
450             break;
451     }
452     return(iresult);
453 }
454 
455 
456 static int
457 IcmpAliasOut1(struct ip *pip)
458 {
459 /*
460     Alias ICMP echo and timestamp packets
461 */
462     struct alias_link *link;
463     struct icmp *ic;
464 
465     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
466 
467 /* Save overwritten data for when echo packet returns */
468     link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id);
469     if (link != NULL)
470     {
471         u_short alias_id;
472         int accumulate;
473 
474         alias_id = GetAliasPort(link);
475 
476 /* Since data field is being modified, adjust ICMP checksum */
477         accumulate  = ic->icmp_id;
478         accumulate -= alias_id;
479         ADJUST_CHECKSUM(accumulate, ic->icmp_cksum)
480 
481 /* Alias sequence number */
482         ic->icmp_id = alias_id;
483 
484 /* Change source address */
485         {
486             struct in_addr alias_address;
487 
488             alias_address = GetAliasAddress(link);
489             DifferentialChecksum(&pip->ip_sum,
490                                  (u_short *) &alias_address,
491                                  (u_short *) &pip->ip_src,
492                                  2);
493             pip->ip_src = alias_address;
494         }
495 
496         return(PKT_ALIAS_OK);
497     }
498     return(PKT_ALIAS_IGNORED);
499 }
500 
501 
502 static int
503 IcmpAliasOut2(struct ip *pip)
504 {
505 /*
506     Alias outgoing ICMP error messages containing
507     IP header and first 64 bits of datagram.
508 */
509     struct in_addr alias_addr;
510     struct ip *ip;
511     struct icmp *ic;
512 
513     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
514     ip = (struct ip *) ic->icmp_data;
515 
516     alias_addr = FindAliasAddress(ip->ip_src);
517 
518 /* Alias destination address in IP fragment */
519     DifferentialChecksum(&ic->icmp_cksum,
520                          (u_short *) &alias_addr,
521                          (u_short *) &ip->ip_dst,
522                          2);
523     ip->ip_dst = alias_addr;
524 
525 /* alias source address in IP header */
526     DifferentialChecksum(&pip->ip_sum,
527                          (u_short *) &alias_addr,
528                          (u_short *) &pip->ip_src,
529                          2);
530     pip->ip_src = alias_addr;
531 
532     return PKT_ALIAS_OK;
533 }
534 
535 
536 static int
537 IcmpAliasOut3(struct ip *pip)
538 {
539 /*
540   Handle outgoing echo and timestamp replies.  The
541   only thing which is done in this case is to alias
542   the source IP address of the packet.
543 */
544     struct in_addr alias_addr;
545 
546     alias_addr = FindAliasAddress(pip->ip_src);
547     DifferentialChecksum(&pip->ip_sum,
548                          (u_short *) &alias_addr,
549                          (u_short *) &pip->ip_src,
550                          2);
551     pip->ip_src = alias_addr;
552 
553     return PKT_ALIAS_OK;
554 }
555 
556 
557 static int
558 IcmpAliasOut(struct ip *pip)
559 {
560     int iresult;
561     struct icmp *ic;
562 
563     ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2));
564 
565     iresult = PKT_ALIAS_IGNORED;
566     switch (ic->icmp_type)
567     {
568         case ICMP_ECHO:
569         case ICMP_TSTAMP:
570             if (ic->icmp_code == 0)
571             {
572                 iresult = IcmpAliasOut1(pip);
573             }
574             break;
575         case ICMP_UNREACH:
576         case ICMP_SOURCEQUENCH:
577         case ICMP_TIMXCEED:
578         case ICMP_PARAMPROB:
579             iresult = IcmpAliasOut2(pip);
580             break;
581         case ICMP_ECHOREPLY:
582         case ICMP_TSTAMPREPLY:
583             iresult = IcmpAliasOut3(pip);
584     }
585     return(iresult);
586 }
587 
588 static int
589 UdpAliasIn(struct ip *pip)
590 {
591     struct udphdr *ud;
592     struct alias_link *link;
593 
594     ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
595 
596     link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
597                         ud->uh_sport, ud->uh_dport,
598                         IPPROTO_UDP);
599     if (link != NULL)
600     {
601         struct in_addr alias_address;
602         struct in_addr original_address;
603         u_short alias_port;
604         int accumulate;
605         u_short *sptr;
606 
607         alias_address = GetAliasAddress(link);
608         original_address = GetOriginalAddress(link);
609         alias_port = ud->uh_dport;
610         ud->uh_dport = GetOriginalPort(link);
611 
612 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
613 		if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
614          || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
615 		{
616             AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport);
617 		} else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
618          || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
619 		{
620             AliasHandleUdpNbtNS(pip, link,
621 								&alias_address,
622 								&alias_port,
623 								&original_address,
624 								&ud->uh_dport );
625 		}
626 
627         if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
628             AliasHandleCUSeeMeIn(pip, original_address);
629 
630 /* If UDP checksum is not zero, then adjust since destination port */
631 /* is being unaliased and destination port is being altered.       */
632         if (ud->uh_sum != 0)
633         {
634             accumulate  = alias_port;
635             accumulate -= ud->uh_dport;
636             sptr = (u_short *) &alias_address;
637             accumulate += *sptr++;
638             accumulate += *sptr;
639             sptr = (u_short *) &original_address;
640             accumulate -= *sptr++;
641             accumulate -= *sptr;
642             ADJUST_CHECKSUM(accumulate, ud->uh_sum)
643         }
644 
645 /* Restore original IP address */
646         DifferentialChecksum(&pip->ip_sum,
647                              (u_short *) &original_address,
648                              (u_short *) &pip->ip_dst,
649                              2);
650         pip->ip_dst = original_address;
651         return(PKT_ALIAS_OK);
652     }
653     return(PKT_ALIAS_IGNORED);
654 }
655 
656 static int
657 UdpAliasOut(struct ip *pip)
658 {
659     struct udphdr *ud;
660     struct alias_link *link;
661 
662     ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
663 
664     link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
665                          ud->uh_sport, ud->uh_dport,
666                          IPPROTO_UDP);
667     if (link != NULL)
668     {
669         u_short alias_port;
670         struct in_addr alias_address;
671 
672         alias_address = GetAliasAddress(link);
673         alias_port = GetAliasPort(link);
674 
675         if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
676             AliasHandleCUSeeMeOut(pip, link);
677 
678 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
679 		if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
680          || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER )
681 		{
682             AliasHandleUdpNbt(pip, link, &alias_address, alias_port);
683 		} else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
684          || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER )
685 		{
686             AliasHandleUdpNbtNS(pip, link,
687 								&pip->ip_src,
688 								&ud->uh_sport,
689 							    &alias_address,
690 							 	&alias_port);
691 		}
692 
693 /* If UDP checksum is not zero, adjust since source port is */
694 /* being aliased and source address is being altered        */
695         if (ud->uh_sum != 0)
696         {
697             int accumulate;
698             u_short *sptr;
699 
700             accumulate  = ud->uh_sport;
701             accumulate -= alias_port;
702             sptr = (u_short *) &(pip->ip_src);
703             accumulate += *sptr++;
704             accumulate += *sptr;
705             sptr = (u_short *) &alias_address;
706             accumulate -= *sptr++;
707             accumulate -= *sptr;
708             ADJUST_CHECKSUM(accumulate, ud->uh_sum)
709         }
710 
711 /* Put alias port in UDP header */
712         ud->uh_sport = alias_port;
713 
714 /* Change source address */
715         DifferentialChecksum(&pip->ip_sum,
716                              (u_short *) &alias_address,
717                              (u_short *) &pip->ip_src,
718                              2);
719         pip->ip_src = alias_address;
720 
721         return(PKT_ALIAS_OK);
722     }
723     return(PKT_ALIAS_IGNORED);
724 }
725 
726 
727 
728 static int
729 TcpAliasIn(struct ip *pip)
730 {
731     struct tcphdr *tc;
732     struct alias_link *link;
733 
734     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
735 
736     link = FindUdpTcpIn(pip->ip_src, pip->ip_dst,
737                         tc->th_sport, tc->th_dport,
738                         IPPROTO_TCP);
739     if (link != NULL)
740     {
741         struct in_addr alias_address;
742         struct in_addr original_address;
743         u_short alias_port;
744         int accumulate;
745         u_short *sptr;
746 
747         alias_address = GetAliasAddress(link);
748         original_address = GetOriginalAddress(link);
749         alias_port = tc->th_dport;
750         tc->th_dport = GetOriginalPort(link);
751 
752 /* Adjust TCP checksum since destination port is being unaliased */
753 /* and destination port is being altered.                        */
754         accumulate  = alias_port;
755         accumulate -= tc->th_dport;
756         sptr = (u_short *) &alias_address;
757         accumulate += *sptr++;
758         accumulate += *sptr;
759         sptr = (u_short *) &original_address;
760         accumulate -= *sptr++;
761         accumulate -= *sptr;
762 
763 /* See if ack number needs to be modified */
764         if (GetAckModified(link) == 1)
765         {
766             int delta;
767 
768             delta = GetDeltaAckIn(pip, link);
769             if (delta != 0)
770             {
771                 sptr = (u_short *) &tc->th_ack;
772                 accumulate += *sptr++;
773                 accumulate += *sptr;
774                 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
775                 sptr = (u_short *) &tc->th_ack;
776                 accumulate -= *sptr++;
777                 accumulate -= *sptr;
778             }
779         }
780 
781         ADJUST_CHECKSUM(accumulate, tc->th_sum);
782 
783 /* Restore original IP address */
784         DifferentialChecksum(&pip->ip_sum,
785                              (u_short *) &original_address,
786                              (u_short *) &pip->ip_dst,
787                              2);
788         pip->ip_dst = original_address;
789 
790 /* Monitor TCP connection state */
791         TcpMonitorIn(pip, link);
792 
793         return(PKT_ALIAS_OK);
794     }
795     return(PKT_ALIAS_IGNORED);
796 }
797 
798 static int
799 TcpAliasOut(struct ip *pip, int maxpacketsize)
800 {
801     struct tcphdr *tc;
802     struct alias_link *link;
803 
804     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
805 
806     link = FindUdpTcpOut(pip->ip_src, pip->ip_dst,
807                          tc->th_sport, tc->th_dport,
808                          IPPROTO_TCP);
809     if (link !=NULL)
810     {
811         struct in_addr alias_address;
812         u_short alias_port;
813         int accumulate;
814         u_short *sptr;
815 
816         alias_port = GetAliasPort(link);
817         alias_address = GetAliasAddress(link);
818 
819 /* Monitor tcp connection state */
820         TcpMonitorOut(pip, link);
821 
822 /* Special processing for ftp connection */
823         if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
824          || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
825             AliasHandleFtpOut(pip, link, maxpacketsize);
826         if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
827                         || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
828             AliasHandleIrcOut(pip, link, maxpacketsize);
829 
830 /* Adjust TCP checksum since source port is being aliased */
831 /* and source address is being altered                    */
832         accumulate  = tc->th_sport;
833         accumulate -= alias_port;
834         sptr = (u_short *) &(pip->ip_src);
835         accumulate += *sptr++;
836         accumulate += *sptr;
837         sptr = (u_short *) &alias_address;
838         accumulate -= *sptr++;
839         accumulate -= *sptr;
840 
841 /* Modify sequence number if necessary */
842         if (GetAckModified(link) == 1)
843         {
844             int delta;
845 
846             delta = GetDeltaSeqOut(pip, link);
847             if (delta != 0)
848             {
849                 sptr = (u_short *) &tc->th_seq;
850                 accumulate += *sptr++;
851                 accumulate += *sptr;
852                 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
853                 sptr = (u_short *) &tc->th_seq;
854                 accumulate -= *sptr++;
855                 accumulate -= *sptr;
856             }
857         }
858 
859         ADJUST_CHECKSUM(accumulate, tc->th_sum)
860 
861 /* Put alias address in TCP header */
862         tc->th_sport = alias_port;
863 
864 /* Change source address */
865         DifferentialChecksum(&pip->ip_sum,
866                              (u_short *) &alias_address,
867                              (u_short *) &pip->ip_src,
868                              2);
869         pip->ip_src = alias_address;
870 
871         return(PKT_ALIAS_OK);
872     }
873     return(PKT_ALIAS_IGNORED);
874 }
875 
876 
877 
878 
879 /* Fragment Handling
880 
881     FragmentIn()
882     FragmentOut()
883 
884 The packet aliasing module has a limited ability for handling IP
885 fragments.  If the ICMP, TCP or UDP header is in the first fragment
886 received, then the id number of the IP packet is saved, and other
887 fragments are identified according to their ID number and IP address
888 they were sent from.  Pointers to unresolved fragments can also be
889 saved and recalled when a header fragment is seen.
890 */
891 
892 /* Local prototypes */
893 static int FragmentIn(struct ip *);
894 static int FragmentOut(struct ip *);
895 
896 
897 static int
898 FragmentIn(struct ip *pip)
899 {
900     struct alias_link *link;
901 
902     link = FindFragmentIn2(pip->ip_src, pip->ip_dst, pip->ip_id);
903     if (link != NULL)
904     {
905         struct in_addr original_address;
906 
907         GetFragmentAddr(link, &original_address);
908         DifferentialChecksum(&pip->ip_sum,
909                              (u_short *) &original_address,
910                              (u_short *) &pip->ip_dst,
911                              2);
912         pip->ip_dst = original_address;
913 
914         return(PKT_ALIAS_OK);
915     }
916     return(PKT_ALIAS_UNRESOLVED_FRAGMENT);
917 }
918 
919 
920 static int
921 FragmentOut(struct ip *pip)
922 {
923     struct in_addr alias_address;
924 
925     alias_address = FindAliasAddress(pip->ip_src);
926     DifferentialChecksum(&pip->ip_sum,
927                          (u_short *) &alias_address,
928                          (u_short *) &pip->ip_src,
929                           2);
930     pip->ip_src = alias_address;
931 
932     return(PKT_ALIAS_OK);
933 }
934 
935 
936 
937 
938 
939 
940 /* Outside World Access
941 
942         PacketAliasSaveFragment()
943         PacketAliasGetFragment()
944         PacketAliasFragmentIn()
945         PacketAliasIn()
946         PacketAliasOut()
947 
948 (prototypes in alias.h)
949 */
950 
951 
952 int
953 PacketAliasSaveFragment(char *ptr)
954 {
955     int iresult;
956     struct alias_link *link;
957     struct ip *pip;
958 
959     pip = (struct ip *) ptr;
960     link = AddFragmentPtrLink(pip->ip_src, pip->ip_id);
961     iresult = PKT_ALIAS_ERROR;
962     if (link != NULL)
963     {
964         SetFragmentPtr(link, ptr);
965         iresult = PKT_ALIAS_OK;
966     }
967     return(iresult);
968 }
969 
970 
971 char *
972 PacketAliasGetFragment(char *ptr)
973 {
974     struct alias_link *link;
975     char *fptr;
976     struct ip *pip;
977 
978     pip = (struct ip *) ptr;
979     link = FindFragmentPtr(pip->ip_src, pip->ip_id);
980     if (link != NULL)
981     {
982         GetFragmentPtr(link, &fptr);
983         SetFragmentPtr(link, NULL);
984         SetExpire(link, 0); /* Deletes link */
985 
986         return(fptr);
987     }
988     else
989     {
990         return(NULL);
991     }
992 }
993 
994 
995 void
996 PacketAliasFragmentIn(char *ptr,          /* Points to correctly de-aliased
997                                              header fragment */
998                       char *ptr_fragment  /* Points to fragment which must
999                                              be de-aliased   */
1000                      )
1001 {
1002     struct ip *pip;
1003     struct ip *fpip;
1004 
1005     pip = (struct ip *) ptr;
1006     fpip = (struct ip *) ptr_fragment;
1007 
1008     DifferentialChecksum(&fpip->ip_sum,
1009                          (u_short *) &pip->ip_dst,
1010                          (u_short *) &fpip->ip_dst,
1011                          2);
1012     fpip->ip_dst = pip->ip_dst;
1013 }
1014 
1015 
1016 int
1017 PacketAliasIn(char *ptr, int maxpacketsize)
1018 {
1019     struct in_addr alias_addr;
1020     struct ip *pip;
1021     int iresult;
1022 
1023     HouseKeeping();
1024     ClearCheckNewLink();
1025     pip = (struct ip *) ptr;
1026     alias_addr = pip->ip_dst;
1027 
1028     /* Defense against mangled packets */
1029     if (ntohs(pip->ip_len) > maxpacketsize
1030      || (pip->ip_hl<<2) > maxpacketsize)
1031         return PKT_ALIAS_IGNORED;
1032 
1033     iresult = PKT_ALIAS_IGNORED;
1034     if ( (ntohs(pip->ip_off) & IP_OFFMASK) == 0 )
1035     {
1036         switch (pip->ip_p)
1037         {
1038             case IPPROTO_ICMP:
1039                 iresult = IcmpAliasIn(pip);
1040                 break;
1041             case IPPROTO_UDP:
1042                 iresult = UdpAliasIn(pip);
1043                 break;
1044             case IPPROTO_TCP:
1045                 iresult = TcpAliasIn(pip);
1046                 break;
1047         }
1048 
1049         if (ntohs(pip->ip_off) & IP_MF)
1050         {
1051             struct alias_link *link;
1052 
1053             link = FindFragmentIn1(pip->ip_src, alias_addr, pip->ip_id);
1054             if (link != NULL)
1055             {
1056                 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1057                 SetFragmentAddr(link, pip->ip_dst);
1058             }
1059             else
1060             {
1061                 iresult = PKT_ALIAS_ERROR;
1062             }
1063         }
1064     }
1065     else
1066     {
1067         iresult = FragmentIn(pip);
1068     }
1069 
1070     return(iresult);
1071 }
1072 
1073 
1074 
1075 /* Unregistered address ranges */
1076 
1077 /* 10.0.0.0   ->   10.255.255.255 */
1078 #define UNREG_ADDR_A_LOWER 0x0a000000
1079 #define UNREG_ADDR_A_UPPER 0x0affffff
1080 
1081 /* 172.16.0.0  ->  172.31.255.255 */
1082 #define UNREG_ADDR_B_LOWER 0xac100000
1083 #define UNREG_ADDR_B_UPPER 0xac1fffff
1084 
1085 /* 192.168.0.0 -> 192.168.255.255 */
1086 #define UNREG_ADDR_C_LOWER 0xc0a80000
1087 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1088 
1089 
1090 
1091 int
1092 PacketAliasOut(char *ptr,           /* valid IP packet */
1093                int  maxpacketsize   /* How much the packet data may grow
1094                                        (FTP and IRC inline changes) */
1095               )
1096 {
1097     int iresult;
1098     struct in_addr addr_save;
1099     struct ip *pip;
1100 
1101     HouseKeeping();
1102     ClearCheckNewLink();
1103     pip = (struct ip *) ptr;
1104 
1105     /* Defense against mangled packets */
1106     if (ntohs(pip->ip_len) > maxpacketsize
1107      || (pip->ip_hl<<2) > maxpacketsize)
1108         return PKT_ALIAS_IGNORED;
1109 
1110     addr_save = GetDefaultAliasAddress();
1111     if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY)
1112     {
1113         unsigned int addr;
1114         int iclass;
1115 
1116         iclass = 0;
1117         addr = ntohl(pip->ip_src.s_addr);
1118         if      (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1119             iclass = 3;
1120         else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1121             iclass = 2;
1122         else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1123             iclass = 1;
1124 
1125         if (iclass == 0)
1126         {
1127             SetDefaultAliasAddress(pip->ip_src);
1128         }
1129     }
1130 
1131     iresult = PKT_ALIAS_IGNORED;
1132     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0)
1133     {
1134         switch (pip->ip_p)
1135         {
1136             case IPPROTO_ICMP:
1137                 iresult = IcmpAliasOut(pip);
1138                 break;
1139             case IPPROTO_UDP:
1140                 iresult = UdpAliasOut(pip);
1141                 break;
1142             case IPPROTO_TCP:
1143                 iresult = TcpAliasOut(pip, maxpacketsize);
1144                 break;
1145         }
1146     }
1147     else
1148     {
1149         iresult = FragmentOut(pip);
1150     }
1151 
1152     SetDefaultAliasAddress(addr_save);
1153     return(iresult);
1154 }
1155