2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3 * Brian Somers <brian@Awfulhak.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/in.h>
36 #include <netinet/ip.h>
37 #include <sys/socket.h>
58 #include "descriptor.h"
62 #include "slcompress.h"
63 #include "throughput.h"
84 #define NAT_EXTRABUF (13)
86 static int StrToAddr(const char *, struct in_addr *);
87 static int StrToPortRange(const char *, u_short *, u_short *, const char *);
88 static int StrToAddrAndPort(const char *, struct in_addr *, u_short *,
89 u_short *, const char *);
91 extern struct libalias *la;
94 lowhigh(u_short *a, u_short *b)
106 nat_RedirectPort(struct cmdargs const *arg)
108 if (!arg->bundle->NatEnabled) {
109 prompt_Printf(arg->prompt, "Alias not enabled\n");
111 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) {
114 struct in_addr localaddr;
115 u_short hlocalport, llocalport;
116 struct in_addr aliasaddr;
117 u_short haliasport, laliasport;
118 struct in_addr remoteaddr;
119 u_short hremoteport, lremoteport;
120 struct alias_link *link;
123 proto = arg->argv[arg->argn];
124 if (strcmp(proto, "tcp") == 0) {
125 proto_constant = IPPROTO_TCP;
126 } else if (strcmp(proto, "udp") == 0) {
127 proto_constant = IPPROTO_UDP;
129 prompt_Printf(arg->prompt, "port redirect: protocol must be"
134 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport,
137 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n");
141 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport,
144 prompt_Printf(arg->prompt, "nat port: error reading alias port\n");
147 aliasaddr.s_addr = INADDR_ANY;
149 if (arg->argc == arg->argn + 4) {
150 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr,
151 &lremoteport, &hremoteport, proto);
153 prompt_Printf(arg->prompt, "nat port: error reading "
154 "remoteaddr:port\n");
158 remoteaddr.s_addr = INADDR_ANY;
159 lremoteport = hremoteport = 0;
162 lowhigh(&llocalport, &hlocalport);
163 lowhigh(&laliasport, &haliasport);
164 lowhigh(&lremoteport, &hremoteport);
166 if (haliasport - laliasport != hlocalport - llocalport) {
167 prompt_Printf(arg->prompt, "nat port: local & alias port ranges "
172 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) {
173 prompt_Printf(arg->prompt, "nat port: local & remote port ranges "
179 link = LibAliasRedirectPort(la, localaddr, htons(llocalport),
180 remoteaddr, htons(lremoteport),
181 aliasaddr, htons(laliasport),
185 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport,
192 } while (laliasport++ < haliasport);
202 nat_RedirectAddr(struct cmdargs const *arg)
204 if (!arg->bundle->NatEnabled) {
205 prompt_Printf(arg->prompt, "nat not enabled\n");
207 } else if (arg->argc == arg->argn+2) {
209 struct in_addr localaddr, aliasaddr;
210 struct alias_link *link;
212 error = StrToAddr(arg->argv[arg->argn], &localaddr);
214 prompt_Printf(arg->prompt, "address redirect: invalid local address\n");
217 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr);
219 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n");
220 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
224 link = LibAliasRedirectAddr(la, localaddr, aliasaddr);
226 prompt_Printf(arg->prompt, "address redirect: packet aliasing"
228 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
239 nat_RedirectProto(struct cmdargs const *arg)
241 if (!arg->bundle->NatEnabled) {
242 prompt_Printf(arg->prompt, "nat not enabled\n");
244 } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) {
245 struct in_addr localIP, publicIP, remoteIP;
246 struct alias_link *link;
251 len = strlen(arg->argv[arg->argn]);
253 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n");
256 if (strspn(arg->argv[arg->argn], "01234567") == len)
257 pe = getprotobynumber(atoi(arg->argv[arg->argn]));
259 pe = getprotobyname(arg->argv[arg->argn]);
261 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n");
265 error = StrToAddr(arg->argv[arg->argn + 1], &localIP);
267 prompt_Printf(arg->prompt, "proto redirect: invalid src address\n");
271 if (arg->argc >= arg->argn + 3) {
272 error = StrToAddr(arg->argv[arg->argn + 2], &publicIP);
274 prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n");
275 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
280 publicIP.s_addr = INADDR_ANY;
282 if (arg->argc == arg->argn + 4) {
283 error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP);
285 prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n");
286 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
291 remoteIP.s_addr = INADDR_ANY;
293 link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto);
295 prompt_Printf(arg->prompt, "proto redirect: packet aliasing"
297 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
308 StrToAddr(const char *str, struct in_addr *addr)
312 if (inet_aton(str, addr))
315 hp = gethostbyname(str);
317 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str);
320 *addr = *((struct in_addr *) hp->h_addr);
326 StrToPort(const char *str, u_short *port, const char *proto)
331 *port = strtol(str, &end, 10);
333 sp = getservbyname(str, proto);
335 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n",
339 *port = ntohs(sp->s_port);
346 StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto)
351 minus = strchr(str, '-');
353 *minus = '\0'; /* Cheat the const-ness ! */
355 res = StrToPort(str, low, proto);
358 *minus = '-'; /* Cheat the const-ness ! */
362 res = StrToPort(minus + 1, high, proto);
371 StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low,
372 u_short *high, const char *proto)
377 colon = strchr(str, ':');
379 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str);
383 *colon = '\0'; /* Cheat the const-ness ! */
384 res = StrToAddr(str, addr);
385 *colon = ':'; /* Cheat the const-ness ! */
389 return StrToPortRange(colon + 1, low, high, proto);
393 nat_ProxyRule(struct cmdargs const *arg)
399 if (arg->argn >= arg->argc)
402 for (f = arg->argn, pos = 0; f < arg->argc; f++) {
403 len = strlen(arg->argv[f]);
404 if (sizeof cmd - pos < len + (len ? 1 : 0))
408 strcpy(cmd + pos, arg->argv[f]);
412 return LibAliasProxyRule(la, cmd);
416 nat_SetTarget(struct cmdargs const *arg)
420 if (arg->argc == arg->argn) {
421 addr.s_addr = INADDR_ANY;
422 LibAliasSetTarget(la, addr);
426 if (arg->argc != arg->argn + 1)
429 if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) {
430 addr.s_addr = INADDR_ANY;
431 LibAliasSetTarget(la, addr);
435 addr = GetIpAddr(arg->argv[arg->argn]);
436 if (addr.s_addr == INADDR_NONE) {
437 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]);
441 LibAliasSetTarget(la, addr);
447 nat_PunchFW(struct cmdargs const *arg)
452 if (arg->argc == arg->argn) {
453 LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW);
457 if (arg->argc != arg->argn + 2)
460 base = strtol(arg->argv[arg->argn], &end, 10);
461 if (*end != '\0' || base < 0)
464 count = strtol(arg->argv[arg->argn + 1], &end, 10);
465 if (*end != '\0' || count < 0)
468 LibAliasSetFWBase(la, base, count);
469 LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
476 nat_SkinnyPort(struct cmdargs const *arg)
481 if (arg->argc == arg->argn) {
482 LibAliasSetSkinnyPort(la, 0);
486 if (arg->argc != arg->argn + 1)
489 port = strtol(arg->argv[arg->argn], &end, 10);
490 if (*end != '\0' || port < 0)
493 LibAliasSetSkinnyPort(la, port);
499 nat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp,
500 int pri __unused, u_short *proto)
502 if (!bundle->NatEnabled || *proto != PROTO_IP)
505 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n");
506 m_settype(bp, MB_NATOUT);
507 /* Ensure there's a bit of extra buffer for the NAT code... */
508 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF));
509 LibAliasOut(la, MBUF_CTOP(bp), bp->m_len);
510 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
516 nat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp,
520 int ret, len, nfrags;
524 if (!bundle->NatEnabled || *proto != PROTO_IP)
527 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n");
528 m_settype(bp, MB_NATIN);
529 /* Ensure there's a bit of extra buffer for the NAT code... */
530 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF));
531 ret = LibAliasIn(la, MBUF_CTOP(bp), bp->m_len);
533 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
534 if (bp->m_len > MAX_MRU) {
535 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n",
536 (unsigned long)bp->m_len);
545 case PKT_ALIAS_UNRESOLVED_FRAGMENT:
546 /* Save the data for later */
547 if ((fptr = malloc(bp->m_len)) == NULL) {
548 log_Printf(LogWARN, "nat_LayerPull: Dropped unresolved fragment -"
549 " out of memory!\n");
553 bp = mbuf_Read(bp, fptr, bp->m_len);
554 LibAliasSaveFragment(la, fptr);
555 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n",
556 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags);
560 case PKT_ALIAS_FOUND_HEADER_FRAGMENT:
561 /* Fetch all the saved fragments and chain them on the end of `bp' */
562 last = &bp->m_nextpkt;
564 while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) {
566 LibAliasFragmentIn(la, MBUF_CTOP(bp), fptr);
567 len = ntohs(((struct ip *)fptr)->ip_len);
568 *last = m_get(len, MB_NATIN);
569 memcpy(MBUF_CTOP(*last), fptr, len);
571 last = &(*last)->m_nextpkt;
574 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no"
575 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id,
579 case PKT_ALIAS_IGNORED:
580 if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) {
581 log_Printf(LogTCPIP, "NAT engine denied data:\n");
584 } else if (log_IsKept(LogTCPIP)) {
585 log_Printf(LogTCPIP, "NAT engine ignored data:\n");
586 PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL,
592 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret);
601 struct layer natlayer =
602 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull };