1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2001 Charles Mott <cm@linktel.net> 5 * Brian Somers <brian@Awfulhak.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/param.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <netdb.h> 36 #include <netinet/in_systm.h> 37 #include <netinet/ip.h> 38 #include <sys/socket.h> 39 #include <sys/un.h> 40 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <termios.h> 46 47 #ifdef LOCALNAT 48 #include "alias.h" 49 #else 50 #include <alias.h> 51 #endif 52 53 #include "layer.h" 54 #include "proto.h" 55 #include "defs.h" 56 #include "command.h" 57 #include "log.h" 58 #include "nat_cmd.h" 59 #include "descriptor.h" 60 #include "prompt.h" 61 #include "timer.h" 62 #include "fsm.h" 63 #include "slcompress.h" 64 #include "throughput.h" 65 #include "iplist.h" 66 #include "mbuf.h" 67 #include "lqr.h" 68 #include "hdlc.h" 69 #include "ncpaddr.h" 70 #include "ip.h" 71 #include "ipcp.h" 72 #include "ipv6cp.h" 73 #include "lcp.h" 74 #include "ccp.h" 75 #include "link.h" 76 #include "mp.h" 77 #include "filter.h" 78 #ifndef NORADIUS 79 #include "radius.h" 80 #endif 81 #include "ncp.h" 82 #include "bundle.h" 83 84 85 #define NAT_EXTRABUF (13) 86 87 static int StrToAddr(const char *, struct in_addr *); 88 static int StrToPortRange(const char *, u_short *, u_short *, const char *); 89 static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 90 u_short *, const char *); 91 92 extern struct libalias *la; 93 94 static void 95 lowhigh(u_short *a, u_short *b) 96 { 97 if (a > b) { 98 u_short c; 99 100 c = *b; 101 *b = *a; 102 *a = c; 103 } 104 } 105 106 int 107 nat_RedirectPort(struct cmdargs const *arg) 108 { 109 if (!arg->bundle->NatEnabled) { 110 prompt_Printf(arg->prompt, "Alias not enabled\n"); 111 return 1; 112 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 113 char proto_constant; 114 const char *proto; 115 struct in_addr localaddr; 116 u_short hlocalport, llocalport; 117 struct in_addr aliasaddr; 118 u_short haliasport, laliasport; 119 struct in_addr remoteaddr; 120 u_short hremoteport, lremoteport; 121 struct alias_link *link; 122 int error; 123 124 proto = arg->argv[arg->argn]; 125 if (strcmp(proto, "tcp") == 0) { 126 proto_constant = IPPROTO_TCP; 127 } else if (strcmp(proto, "udp") == 0) { 128 proto_constant = IPPROTO_UDP; 129 } else { 130 prompt_Printf(arg->prompt, "port redirect: protocol must be" 131 " tcp or udp\n"); 132 return -1; 133 } 134 135 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 136 &hlocalport, proto); 137 if (error) { 138 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 139 return -1; 140 } 141 142 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 143 proto); 144 if (error) { 145 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 146 return -1; 147 } 148 aliasaddr.s_addr = INADDR_ANY; 149 150 if (arg->argc == arg->argn + 4) { 151 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 152 &lremoteport, &hremoteport, proto); 153 if (error) { 154 prompt_Printf(arg->prompt, "nat port: error reading " 155 "remoteaddr:port\n"); 156 return -1; 157 } 158 } else { 159 remoteaddr.s_addr = INADDR_ANY; 160 lremoteport = hremoteport = 0; 161 } 162 163 lowhigh(&llocalport, &hlocalport); 164 lowhigh(&laliasport, &haliasport); 165 lowhigh(&lremoteport, &hremoteport); 166 167 if (haliasport - laliasport != hlocalport - llocalport) { 168 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 169 "are not equal\n"); 170 return -1; 171 } 172 173 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 174 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 175 "are not equal\n"); 176 return -1; 177 } 178 179 do { 180 link = LibAliasRedirectPort(la, localaddr, htons(llocalport), 181 remoteaddr, htons(lremoteport), 182 aliasaddr, htons(laliasport), 183 proto_constant); 184 185 if (link == NULL) { 186 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 187 error); 188 return 1; 189 } 190 llocalport++; 191 if (hremoteport) 192 lremoteport++; 193 } while (laliasport++ < haliasport); 194 195 return 0; 196 } 197 198 return -1; 199 } 200 201 202 int 203 nat_RedirectAddr(struct cmdargs const *arg) 204 { 205 if (!arg->bundle->NatEnabled) { 206 prompt_Printf(arg->prompt, "nat not enabled\n"); 207 return 1; 208 } else if (arg->argc == arg->argn+2) { 209 int error; 210 struct in_addr localaddr, aliasaddr; 211 struct alias_link *link; 212 213 error = StrToAddr(arg->argv[arg->argn], &localaddr); 214 if (error) { 215 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 216 return 1; 217 } 218 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 219 if (error) { 220 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 221 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 222 arg->cmd->syntax); 223 return 1; 224 } 225 link = LibAliasRedirectAddr(la, localaddr, aliasaddr); 226 if (link == NULL) { 227 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 228 " engine error\n"); 229 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 230 arg->cmd->syntax); 231 } 232 } else 233 return -1; 234 235 return 0; 236 } 237 238 239 int 240 nat_RedirectProto(struct cmdargs const *arg) 241 { 242 if (!arg->bundle->NatEnabled) { 243 prompt_Printf(arg->prompt, "nat not enabled\n"); 244 return 1; 245 } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) { 246 struct in_addr localIP, publicIP, remoteIP; 247 struct alias_link *link; 248 struct protoent *pe; 249 int error; 250 unsigned len; 251 252 len = strlen(arg->argv[arg->argn]); 253 if (len == 0) { 254 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 255 return 1; 256 } 257 if (strspn(arg->argv[arg->argn], "01234567") == len) 258 pe = getprotobynumber(atoi(arg->argv[arg->argn])); 259 else 260 pe = getprotobyname(arg->argv[arg->argn]); 261 if (pe == NULL) { 262 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 263 return 1; 264 } 265 266 error = StrToAddr(arg->argv[arg->argn + 1], &localIP); 267 if (error) { 268 prompt_Printf(arg->prompt, "proto redirect: invalid src address\n"); 269 return 1; 270 } 271 272 if (arg->argc >= arg->argn + 3) { 273 error = StrToAddr(arg->argv[arg->argn + 2], &publicIP); 274 if (error) { 275 prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n"); 276 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 277 arg->cmd->syntax); 278 return 1; 279 } 280 } else 281 publicIP.s_addr = INADDR_ANY; 282 283 if (arg->argc == arg->argn + 4) { 284 error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP); 285 if (error) { 286 prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n"); 287 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 288 arg->cmd->syntax); 289 return 1; 290 } 291 } else 292 remoteIP.s_addr = INADDR_ANY; 293 294 link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto); 295 if (link == NULL) { 296 prompt_Printf(arg->prompt, "proto redirect: packet aliasing" 297 " engine error\n"); 298 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 299 arg->cmd->syntax); 300 } 301 } else 302 return -1; 303 304 return 0; 305 } 306 307 308 static int 309 StrToAddr(const char *str, struct in_addr *addr) 310 { 311 struct hostent *hp; 312 313 if (inet_aton(str, addr)) 314 return 0; 315 316 hp = gethostbyname(str); 317 if (!hp) { 318 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 319 return -1; 320 } 321 *addr = *((struct in_addr *) hp->h_addr); 322 return 0; 323 } 324 325 326 static int 327 StrToPort(const char *str, u_short *port, const char *proto) 328 { 329 struct servent *sp; 330 char *end; 331 332 *port = strtol(str, &end, 10); 333 if (*end != '\0') { 334 sp = getservbyname(str, proto); 335 if (sp == NULL) { 336 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 337 str, proto); 338 return -1; 339 } 340 *port = ntohs(sp->s_port); 341 } 342 343 return 0; 344 } 345 346 static int 347 StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 348 { 349 char *minus; 350 int res; 351 352 minus = strchr(str, '-'); 353 if (minus) 354 *minus = '\0'; /* Cheat the const-ness ! */ 355 356 res = StrToPort(str, low, proto); 357 358 if (minus) 359 *minus = '-'; /* Cheat the const-ness ! */ 360 361 if (res == 0) { 362 if (minus) 363 res = StrToPort(minus + 1, high, proto); 364 else 365 *high = *low; 366 } 367 368 return res; 369 } 370 371 static int 372 StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 373 u_short *high, const char *proto) 374 { 375 char *colon; 376 int res; 377 378 colon = strchr(str, ':'); 379 if (!colon) { 380 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 381 return -1; 382 } 383 384 *colon = '\0'; /* Cheat the const-ness ! */ 385 res = StrToAddr(str, addr); 386 *colon = ':'; /* Cheat the const-ness ! */ 387 if (res != 0) 388 return -1; 389 390 return StrToPortRange(colon + 1, low, high, proto); 391 } 392 393 int 394 nat_ProxyRule(struct cmdargs const *arg) 395 { 396 char cmd[LINE_LEN]; 397 int f, pos; 398 size_t len; 399 400 if (arg->argn >= arg->argc) 401 return -1; 402 403 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 404 len = strlen(arg->argv[f]); 405 if (sizeof cmd - pos < len + (len ? 1 : 0)) 406 break; 407 if (len) 408 cmd[pos++] = ' '; 409 strcpy(cmd + pos, arg->argv[f]); 410 pos += len; 411 } 412 413 return LibAliasProxyRule(la, cmd); 414 } 415 416 int 417 nat_SetTarget(struct cmdargs const *arg) 418 { 419 struct in_addr addr; 420 421 if (arg->argc == arg->argn) { 422 addr.s_addr = INADDR_ANY; 423 LibAliasSetTarget(la, addr); 424 return 0; 425 } 426 427 if (arg->argc != arg->argn + 1) 428 return -1; 429 430 if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { 431 addr.s_addr = INADDR_ANY; 432 LibAliasSetTarget(la, addr); 433 return 0; 434 } 435 436 addr = GetIpAddr(arg->argv[arg->argn]); 437 if (addr.s_addr == INADDR_NONE) { 438 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 439 return 1; 440 } 441 442 LibAliasSetTarget(la, addr); 443 return 0; 444 } 445 446 #ifndef NO_FW_PUNCH 447 int 448 nat_PunchFW(struct cmdargs const *arg) 449 { 450 char *end; 451 long base, count; 452 453 if (arg->argc == arg->argn) { 454 LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW); 455 return 0; 456 } 457 458 if (arg->argc != arg->argn + 2) 459 return -1; 460 461 base = strtol(arg->argv[arg->argn], &end, 10); 462 if (*end != '\0' || base < 0) 463 return -1; 464 465 count = strtol(arg->argv[arg->argn + 1], &end, 10); 466 if (*end != '\0' || count < 0) 467 return -1; 468 469 LibAliasSetFWBase(la, base, count); 470 LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 471 472 return 0; 473 } 474 #endif 475 476 int 477 nat_SkinnyPort(struct cmdargs const *arg) 478 { 479 char *end; 480 long port; 481 482 if (arg->argc == arg->argn) { 483 LibAliasSetSkinnyPort(la, 0); 484 return 0; 485 } 486 487 if (arg->argc != arg->argn + 1) 488 return -1; 489 490 port = strtol(arg->argv[arg->argn], &end, 10); 491 if (*end != '\0' || port < 0) 492 return -1; 493 494 LibAliasSetSkinnyPort(la, port); 495 496 return 0; 497 } 498 499 static struct mbuf * 500 nat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, 501 int pri __unused, u_short *proto) 502 { 503 if (!bundle->NatEnabled || *proto != PROTO_IP) 504 return bp; 505 506 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 507 m_settype(bp, MB_NATOUT); 508 /* Ensure there's a bit of extra buffer for the NAT code... */ 509 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 510 LibAliasOut(la, MBUF_CTOP(bp), bp->m_len); 511 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 512 513 return bp; 514 } 515 516 static struct mbuf * 517 nat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, 518 u_short *proto) 519 { 520 static int gfrags; 521 int ret, len, nfrags; 522 struct mbuf **last; 523 char *fptr; 524 525 if (!bundle->NatEnabled || *proto != PROTO_IP) 526 return bp; 527 528 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 529 m_settype(bp, MB_NATIN); 530 /* Ensure there's a bit of extra buffer for the NAT code... */ 531 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 532 ret = LibAliasIn(la, MBUF_CTOP(bp), bp->m_len); 533 534 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 535 if (bp->m_len > MAX_MRU) { 536 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 537 (unsigned long)bp->m_len); 538 m_freem(bp); 539 return NULL; 540 } 541 542 switch (ret) { 543 case PKT_ALIAS_OK: 544 break; 545 546 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 547 /* Save the data for later */ 548 if ((fptr = malloc(bp->m_len)) == NULL) { 549 log_Printf(LogWARN, "nat_LayerPull: Dropped unresolved fragment -" 550 " out of memory!\n"); 551 m_freem(bp); 552 bp = NULL; 553 } else { 554 bp = mbuf_Read(bp, fptr, bp->m_len); 555 LibAliasSaveFragment(la, fptr); 556 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 557 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 558 } 559 break; 560 561 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 562 /* Fetch all the saved fragments and chain them on the end of `bp' */ 563 last = &bp->m_nextpkt; 564 nfrags = 0; 565 while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) { 566 nfrags++; 567 LibAliasFragmentIn(la, MBUF_CTOP(bp), fptr); 568 len = ntohs(((struct ip *)fptr)->ip_len); 569 *last = m_get(len, MB_NATIN); 570 memcpy(MBUF_CTOP(*last), fptr, len); 571 free(fptr); 572 last = &(*last)->m_nextpkt; 573 } 574 gfrags -= nfrags; 575 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 576 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 577 nfrags, gfrags); 578 break; 579 580 case PKT_ALIAS_IGNORED: 581 if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) { 582 log_Printf(LogTCPIP, "NAT engine denied data:\n"); 583 m_freem(bp); 584 bp = NULL; 585 } else if (log_IsKept(LogTCPIP)) { 586 log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 587 PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL, 588 NULL, NULL); 589 } 590 break; 591 592 default: 593 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 594 m_freem(bp); 595 bp = NULL; 596 break; 597 } 598 599 return bp; 600 } 601 602 struct layer natlayer = 603 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 604