1 /*- 2 * Copyright (c) 2001 Charles Mott <cm@linktel.net> 3 * Brian Somers <brian@Awfulhak.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/param.h> 31 #include <netinet/in.h> 32 #include <arpa/inet.h> 33 #include <netdb.h> 34 #include <netinet/in_systm.h> 35 #include <netinet/in.h> 36 #include <netinet/ip.h> 37 #include <sys/socket.h> 38 #include <sys/un.h> 39 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <termios.h> 45 46 #ifdef LOCALNAT 47 #include "alias.h" 48 #else 49 #include <alias.h> 50 #endif 51 52 #include "layer.h" 53 #include "proto.h" 54 #include "defs.h" 55 #include "command.h" 56 #include "log.h" 57 #include "nat_cmd.h" 58 #include "descriptor.h" 59 #include "prompt.h" 60 #include "timer.h" 61 #include "fsm.h" 62 #include "slcompress.h" 63 #include "throughput.h" 64 #include "iplist.h" 65 #include "mbuf.h" 66 #include "lqr.h" 67 #include "hdlc.h" 68 #include "ncpaddr.h" 69 #include "ip.h" 70 #include "ipcp.h" 71 #include "ipv6cp.h" 72 #include "lcp.h" 73 #include "ccp.h" 74 #include "link.h" 75 #include "mp.h" 76 #include "filter.h" 77 #ifndef NORADIUS 78 #include "radius.h" 79 #endif 80 #include "ncp.h" 81 #include "bundle.h" 82 83 84 #define NAT_EXTRABUF (13) 85 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 *); 90 91 extern struct libalias *la; 92 93 static void 94 lowhigh(u_short *a, u_short *b) 95 { 96 if (a > b) { 97 u_short c; 98 99 c = *b; 100 *b = *a; 101 *a = c; 102 } 103 } 104 105 int 106 nat_RedirectPort(struct cmdargs const *arg) 107 { 108 if (!arg->bundle->NatEnabled) { 109 prompt_Printf(arg->prompt, "Alias not enabled\n"); 110 return 1; 111 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 112 char proto_constant; 113 const char *proto; 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; 121 int error; 122 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; 128 } else { 129 prompt_Printf(arg->prompt, "port redirect: protocol must be" 130 " tcp or udp\n"); 131 return -1; 132 } 133 134 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 135 &hlocalport, proto); 136 if (error) { 137 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 138 return -1; 139 } 140 141 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 142 proto); 143 if (error) { 144 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 145 return -1; 146 } 147 aliasaddr.s_addr = INADDR_ANY; 148 149 if (arg->argc == arg->argn + 4) { 150 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 151 &lremoteport, &hremoteport, proto); 152 if (error) { 153 prompt_Printf(arg->prompt, "nat port: error reading " 154 "remoteaddr:port\n"); 155 return -1; 156 } 157 } else { 158 remoteaddr.s_addr = INADDR_ANY; 159 lremoteport = hremoteport = 0; 160 } 161 162 lowhigh(&llocalport, &hlocalport); 163 lowhigh(&laliasport, &haliasport); 164 lowhigh(&lremoteport, &hremoteport); 165 166 if (haliasport - laliasport != hlocalport - llocalport) { 167 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 168 "are not equal\n"); 169 return -1; 170 } 171 172 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 173 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 174 "are not equal\n"); 175 return -1; 176 } 177 178 do { 179 link = LibAliasRedirectPort(la, localaddr, htons(llocalport), 180 remoteaddr, htons(lremoteport), 181 aliasaddr, htons(laliasport), 182 proto_constant); 183 184 if (link == NULL) { 185 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 186 error); 187 return 1; 188 } 189 llocalport++; 190 if (hremoteport) 191 lremoteport++; 192 } while (laliasport++ < haliasport); 193 194 return 0; 195 } 196 197 return -1; 198 } 199 200 201 int 202 nat_RedirectAddr(struct cmdargs const *arg) 203 { 204 if (!arg->bundle->NatEnabled) { 205 prompt_Printf(arg->prompt, "nat not enabled\n"); 206 return 1; 207 } else if (arg->argc == arg->argn+2) { 208 int error; 209 struct in_addr localaddr, aliasaddr; 210 struct alias_link *link; 211 212 error = StrToAddr(arg->argv[arg->argn], &localaddr); 213 if (error) { 214 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 215 return 1; 216 } 217 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 218 if (error) { 219 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 220 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 221 arg->cmd->syntax); 222 return 1; 223 } 224 link = LibAliasRedirectAddr(la, localaddr, aliasaddr); 225 if (link == NULL) { 226 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 227 " engine error\n"); 228 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 229 arg->cmd->syntax); 230 } 231 } else 232 return -1; 233 234 return 0; 235 } 236 237 238 int 239 nat_RedirectProto(struct cmdargs const *arg) 240 { 241 if (!arg->bundle->NatEnabled) { 242 prompt_Printf(arg->prompt, "nat not enabled\n"); 243 return 1; 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; 247 struct protoent *pe; 248 int error; 249 unsigned len; 250 251 len = strlen(arg->argv[arg->argn]); 252 if (len == 0) { 253 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 254 return 1; 255 } 256 if (strspn(arg->argv[arg->argn], "01234567") == len) 257 pe = getprotobynumber(atoi(arg->argv[arg->argn])); 258 else 259 pe = getprotobyname(arg->argv[arg->argn]); 260 if (pe == NULL) { 261 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 262 return 1; 263 } 264 265 error = StrToAddr(arg->argv[arg->argn + 1], &localIP); 266 if (error) { 267 prompt_Printf(arg->prompt, "proto redirect: invalid src address\n"); 268 return 1; 269 } 270 271 if (arg->argc >= arg->argn + 3) { 272 error = StrToAddr(arg->argv[arg->argn + 2], &publicIP); 273 if (error) { 274 prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n"); 275 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 276 arg->cmd->syntax); 277 return 1; 278 } 279 } else 280 publicIP.s_addr = INADDR_ANY; 281 282 if (arg->argc == arg->argn + 4) { 283 error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP); 284 if (error) { 285 prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n"); 286 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 287 arg->cmd->syntax); 288 return 1; 289 } 290 } else 291 remoteIP.s_addr = INADDR_ANY; 292 293 link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto); 294 if (link == NULL) { 295 prompt_Printf(arg->prompt, "proto redirect: packet aliasing" 296 " engine error\n"); 297 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 298 arg->cmd->syntax); 299 } 300 } else 301 return -1; 302 303 return 0; 304 } 305 306 307 static int 308 StrToAddr(const char *str, struct in_addr *addr) 309 { 310 struct hostent *hp; 311 312 if (inet_aton(str, addr)) 313 return 0; 314 315 hp = gethostbyname(str); 316 if (!hp) { 317 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 318 return -1; 319 } 320 *addr = *((struct in_addr *) hp->h_addr); 321 return 0; 322 } 323 324 325 static int 326 StrToPort(const char *str, u_short *port, const char *proto) 327 { 328 struct servent *sp; 329 char *end; 330 331 *port = strtol(str, &end, 10); 332 if (*end != '\0') { 333 sp = getservbyname(str, proto); 334 if (sp == NULL) { 335 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 336 str, proto); 337 return -1; 338 } 339 *port = ntohs(sp->s_port); 340 } 341 342 return 0; 343 } 344 345 static int 346 StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 347 { 348 char *minus; 349 int res; 350 351 minus = strchr(str, '-'); 352 if (minus) 353 *minus = '\0'; /* Cheat the const-ness ! */ 354 355 res = StrToPort(str, low, proto); 356 357 if (minus) 358 *minus = '-'; /* Cheat the const-ness ! */ 359 360 if (res == 0) { 361 if (minus) 362 res = StrToPort(minus + 1, high, proto); 363 else 364 *high = *low; 365 } 366 367 return res; 368 } 369 370 static int 371 StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 372 u_short *high, const char *proto) 373 { 374 char *colon; 375 int res; 376 377 colon = strchr(str, ':'); 378 if (!colon) { 379 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 380 return -1; 381 } 382 383 *colon = '\0'; /* Cheat the const-ness ! */ 384 res = StrToAddr(str, addr); 385 *colon = ':'; /* Cheat the const-ness ! */ 386 if (res != 0) 387 return -1; 388 389 return StrToPortRange(colon + 1, low, high, proto); 390 } 391 392 int 393 nat_ProxyRule(struct cmdargs const *arg) 394 { 395 char cmd[LINE_LEN]; 396 int f, pos; 397 size_t len; 398 399 if (arg->argn >= arg->argc) 400 return -1; 401 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)) 405 break; 406 if (len) 407 cmd[pos++] = ' '; 408 strcpy(cmd + pos, arg->argv[f]); 409 pos += len; 410 } 411 412 return LibAliasProxyRule(la, cmd); 413 } 414 415 int 416 nat_SetTarget(struct cmdargs const *arg) 417 { 418 struct in_addr addr; 419 420 if (arg->argc == arg->argn) { 421 addr.s_addr = INADDR_ANY; 422 LibAliasSetTarget(la, addr); 423 return 0; 424 } 425 426 if (arg->argc != arg->argn + 1) 427 return -1; 428 429 if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { 430 addr.s_addr = INADDR_ANY; 431 LibAliasSetTarget(la, addr); 432 return 0; 433 } 434 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]); 438 return 1; 439 } 440 441 LibAliasSetTarget(la, addr); 442 return 0; 443 } 444 445 #ifndef NO_FW_PUNCH 446 int 447 nat_PunchFW(struct cmdargs const *arg) 448 { 449 char *end; 450 long base, count; 451 452 if (arg->argc == arg->argn) { 453 LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW); 454 return 0; 455 } 456 457 if (arg->argc != arg->argn + 2) 458 return -1; 459 460 base = strtol(arg->argv[arg->argn], &end, 10); 461 if (*end != '\0' || base < 0) 462 return -1; 463 464 count = strtol(arg->argv[arg->argn + 1], &end, 10); 465 if (*end != '\0' || count < 0) 466 return -1; 467 468 LibAliasSetFWBase(la, base, count); 469 LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 470 471 return 0; 472 } 473 #endif 474 475 int 476 nat_SkinnyPort(struct cmdargs const *arg) 477 { 478 char *end; 479 long port; 480 481 if (arg->argc == arg->argn) { 482 LibAliasSetSkinnyPort(la, 0); 483 return 0; 484 } 485 486 if (arg->argc != arg->argn + 1) 487 return -1; 488 489 port = strtol(arg->argv[arg->argn], &end, 10); 490 if (*end != '\0' || port < 0) 491 return -1; 492 493 LibAliasSetSkinnyPort(la, port); 494 495 return 0; 496 } 497 498 static struct mbuf * 499 nat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, 500 int pri __unused, u_short *proto) 501 { 502 if (!bundle->NatEnabled || *proto != PROTO_IP) 503 return bp; 504 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); 511 512 return bp; 513 } 514 515 static struct mbuf * 516 nat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, 517 u_short *proto) 518 { 519 static int gfrags; 520 int ret, len, nfrags; 521 struct mbuf **last; 522 char *fptr; 523 524 if (!bundle->NatEnabled || *proto != PROTO_IP) 525 return bp; 526 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); 532 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); 537 m_freem(bp); 538 return NULL; 539 } 540 541 switch (ret) { 542 case PKT_ALIAS_OK: 543 break; 544 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"); 550 m_freem(bp); 551 bp = NULL; 552 } else { 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); 557 } 558 break; 559 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; 563 nfrags = 0; 564 while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) { 565 nfrags++; 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); 570 free(fptr); 571 last = &(*last)->m_nextpkt; 572 } 573 gfrags -= nfrags; 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, 576 nfrags, gfrags); 577 break; 578 579 case PKT_ALIAS_IGNORED: 580 if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) { 581 log_Printf(LogTCPIP, "NAT engine denied data:\n"); 582 m_freem(bp); 583 bp = NULL; 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, 587 NULL, NULL); 588 } 589 break; 590 591 default: 592 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 593 m_freem(bp); 594 bp = NULL; 595 break; 596 } 597 598 return bp; 599 } 600 601 struct layer natlayer = 602 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 603