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