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 <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <termios.h> 44 45 #ifdef LOCALNAT 46 #include "alias.h" 47 #else 48 #include <alias.h> 49 #endif 50 51 #include "layer.h" 52 #include "proto.h" 53 #include "defs.h" 54 #include "command.h" 55 #include "log.h" 56 #include "nat_cmd.h" 57 #include "descriptor.h" 58 #include "prompt.h" 59 #include "timer.h" 60 #include "fsm.h" 61 #include "slcompress.h" 62 #include "throughput.h" 63 #include "iplist.h" 64 #include "mbuf.h" 65 #include "lqr.h" 66 #include "hdlc.h" 67 #include "ncpaddr.h" 68 #include "ip.h" 69 #include "ipcp.h" 70 #include "ipv6cp.h" 71 #include "lcp.h" 72 #include "ccp.h" 73 #include "link.h" 74 #include "mp.h" 75 #include "filter.h" 76 #ifndef NORADIUS 77 #include "radius.h" 78 #endif 79 #include "ncp.h" 80 #include "bundle.h" 81 82 83 #define NAT_EXTRABUF (13) 84 85 static int StrToAddr(const char *, struct in_addr *); 86 static int StrToPortRange(const char *, u_short *, u_short *, const char *); 87 static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 88 u_short *, const char *); 89 90 static void 91 lowhigh(u_short *a, u_short *b) 92 { 93 if (a > b) { 94 u_short c; 95 96 c = *b; 97 *b = *a; 98 *a = c; 99 } 100 } 101 102 int 103 nat_RedirectPort(struct cmdargs const *arg) 104 { 105 if (!arg->bundle->NatEnabled) { 106 prompt_Printf(arg->prompt, "Alias not enabled\n"); 107 return 1; 108 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 109 char proto_constant; 110 const char *proto; 111 struct in_addr localaddr; 112 u_short hlocalport, llocalport; 113 struct in_addr aliasaddr; 114 u_short haliasport, laliasport; 115 struct in_addr remoteaddr; 116 u_short hremoteport, lremoteport; 117 struct alias_link *link; 118 int error; 119 120 proto = arg->argv[arg->argn]; 121 if (strcmp(proto, "tcp") == 0) { 122 proto_constant = IPPROTO_TCP; 123 } else if (strcmp(proto, "udp") == 0) { 124 proto_constant = IPPROTO_UDP; 125 } else { 126 prompt_Printf(arg->prompt, "port redirect: protocol must be" 127 " tcp or udp\n"); 128 return -1; 129 } 130 131 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 132 &hlocalport, proto); 133 if (error) { 134 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 135 return -1; 136 } 137 138 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 139 proto); 140 if (error) { 141 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 142 return -1; 143 } 144 aliasaddr.s_addr = INADDR_ANY; 145 146 if (arg->argc == arg->argn + 4) { 147 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 148 &lremoteport, &hremoteport, proto); 149 if (error) { 150 prompt_Printf(arg->prompt, "nat port: error reading " 151 "remoteaddr:port\n"); 152 return -1; 153 } 154 } else { 155 remoteaddr.s_addr = INADDR_ANY; 156 lremoteport = hremoteport = 0; 157 } 158 159 lowhigh(&llocalport, &hlocalport); 160 lowhigh(&laliasport, &haliasport); 161 lowhigh(&lremoteport, &hremoteport); 162 163 if (haliasport - laliasport != hlocalport - llocalport) { 164 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 165 "are not equal\n"); 166 return -1; 167 } 168 169 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 170 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 171 "are not equal\n"); 172 return -1; 173 } 174 175 while (laliasport <= haliasport) { 176 link = PacketAliasRedirectPort(localaddr, htons(llocalport), 177 remoteaddr, htons(lremoteport), 178 aliasaddr, htons(laliasport), 179 proto_constant); 180 181 if (link == NULL) { 182 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 183 error); 184 return 1; 185 } 186 llocalport++; 187 laliasport++; 188 if (hremoteport) 189 lremoteport++; 190 } 191 192 return 0; 193 } 194 195 return -1; 196 } 197 198 199 int 200 nat_RedirectAddr(struct cmdargs const *arg) 201 { 202 if (!arg->bundle->NatEnabled) { 203 prompt_Printf(arg->prompt, "nat not enabled\n"); 204 return 1; 205 } else if (arg->argc == arg->argn+2) { 206 int error; 207 struct in_addr localaddr, aliasaddr; 208 struct alias_link *link; 209 210 error = StrToAddr(arg->argv[arg->argn], &localaddr); 211 if (error) { 212 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 213 return 1; 214 } 215 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 216 if (error) { 217 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 218 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 219 arg->cmd->syntax); 220 return 1; 221 } 222 link = PacketAliasRedirectAddr(localaddr, aliasaddr); 223 if (link == NULL) { 224 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 225 " engine error\n"); 226 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 227 arg->cmd->syntax); 228 } 229 } else 230 return -1; 231 232 return 0; 233 } 234 235 236 int 237 nat_RedirectProto(struct cmdargs const *arg) 238 { 239 if (!arg->bundle->NatEnabled) { 240 prompt_Printf(arg->prompt, "nat not enabled\n"); 241 return 1; 242 } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) { 243 struct in_addr localIP, publicIP, remoteIP; 244 struct alias_link *link; 245 struct protoent *pe; 246 int error, len; 247 248 len = strlen(arg->argv[arg->argn]); 249 if (len == 0) { 250 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 251 return 1; 252 } 253 if (strspn(arg->argv[arg->argn], "01234567") == len) 254 pe = getprotobynumber(atoi(arg->argv[arg->argn])); 255 else 256 pe = getprotobyname(arg->argv[arg->argn]); 257 if (pe == NULL) { 258 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 259 return 1; 260 } 261 262 error = StrToAddr(arg->argv[arg->argn + 1], &localIP); 263 if (error) { 264 prompt_Printf(arg->prompt, "proto redirect: invalid src address\n"); 265 return 1; 266 } 267 268 if (arg->argc >= arg->argn + 3) { 269 error = StrToAddr(arg->argv[arg->argn + 2], &publicIP); 270 if (error) { 271 prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n"); 272 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 273 arg->cmd->syntax); 274 return 1; 275 } 276 } else 277 publicIP.s_addr = INADDR_ANY; 278 279 if (arg->argc == arg->argn + 4) { 280 error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP); 281 if (error) { 282 prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n"); 283 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 284 arg->cmd->syntax); 285 return 1; 286 } 287 } else 288 remoteIP.s_addr = INADDR_ANY; 289 290 link = PacketAliasRedirectProto(localIP, remoteIP, publicIP, pe->p_proto); 291 if (link == NULL) { 292 prompt_Printf(arg->prompt, "proto redirect: packet aliasing" 293 " engine error\n"); 294 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 295 arg->cmd->syntax); 296 } 297 } else 298 return -1; 299 300 return 0; 301 } 302 303 304 static int 305 StrToAddr(const char *str, struct in_addr *addr) 306 { 307 struct hostent *hp; 308 309 if (inet_aton(str, addr)) 310 return 0; 311 312 hp = gethostbyname(str); 313 if (!hp) { 314 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 315 return -1; 316 } 317 *addr = *((struct in_addr *) hp->h_addr); 318 return 0; 319 } 320 321 322 static int 323 StrToPort(const char *str, u_short *port, const char *proto) 324 { 325 struct servent *sp; 326 char *end; 327 328 *port = strtol(str, &end, 10); 329 if (*end != '\0') { 330 sp = getservbyname(str, proto); 331 if (sp == NULL) { 332 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 333 str, proto); 334 return -1; 335 } 336 *port = ntohs(sp->s_port); 337 } 338 339 return 0; 340 } 341 342 static int 343 StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 344 { 345 char *minus; 346 int res; 347 348 minus = strchr(str, '-'); 349 if (minus) 350 *minus = '\0'; /* Cheat the const-ness ! */ 351 352 res = StrToPort(str, low, proto); 353 354 if (minus) 355 *minus = '-'; /* Cheat the const-ness ! */ 356 357 if (res == 0) { 358 if (minus) 359 res = StrToPort(minus + 1, high, proto); 360 else 361 *high = *low; 362 } 363 364 return res; 365 } 366 367 static int 368 StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 369 u_short *high, const char *proto) 370 { 371 char *colon; 372 int res; 373 374 colon = strchr(str, ':'); 375 if (!colon) { 376 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 377 return -1; 378 } 379 380 *colon = '\0'; /* Cheat the const-ness ! */ 381 res = StrToAddr(str, addr); 382 *colon = ':'; /* Cheat the const-ness ! */ 383 if (res != 0) 384 return -1; 385 386 return StrToPortRange(colon + 1, low, high, proto); 387 } 388 389 int 390 nat_ProxyRule(struct cmdargs const *arg) 391 { 392 char cmd[LINE_LEN]; 393 int f, pos; 394 size_t len; 395 396 if (arg->argn >= arg->argc) 397 return -1; 398 399 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 400 len = strlen(arg->argv[f]); 401 if (sizeof cmd - pos < len + (len ? 1 : 0)) 402 break; 403 if (len) 404 cmd[pos++] = ' '; 405 strcpy(cmd + pos, arg->argv[f]); 406 pos += len; 407 } 408 409 return PacketAliasProxyRule(cmd); 410 } 411 412 int 413 nat_SetTarget(struct cmdargs const *arg) 414 { 415 struct in_addr addr; 416 417 if (arg->argc == arg->argn) { 418 addr.s_addr = INADDR_ANY; 419 PacketAliasSetTarget(addr); 420 return 0; 421 } 422 423 if (arg->argc != arg->argn + 1) 424 return -1; 425 426 if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { 427 addr.s_addr = INADDR_ANY; 428 PacketAliasSetTarget(addr); 429 return 0; 430 } 431 432 addr = GetIpAddr(arg->argv[arg->argn]); 433 if (addr.s_addr == INADDR_NONE) { 434 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 435 return 1; 436 } 437 438 PacketAliasSetTarget(addr); 439 return 0; 440 } 441 442 #ifndef NO_FW_PUNCH 443 int 444 nat_PunchFW(struct cmdargs const *arg) 445 { 446 char *end; 447 long base, count; 448 449 if (arg->argc == arg->argn) { 450 PacketAliasSetMode(0, PKT_ALIAS_PUNCH_FW); 451 return 0; 452 } 453 454 if (arg->argc != arg->argn + 2) 455 return -1; 456 457 base = strtol(arg->argv[arg->argn], &end, 10); 458 if (*end != '\0' || base < 0) 459 return -1; 460 461 count = strtol(arg->argv[arg->argn + 1], &end, 10); 462 if (*end != '\0' || count < 0) 463 return -1; 464 465 PacketAliasSetFWBase(base, count); 466 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 467 468 return 0; 469 } 470 #endif 471 472 static struct mbuf * 473 nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 474 int pri, u_short *proto) 475 { 476 if (!bundle->NatEnabled || *proto != PROTO_IP) 477 return bp; 478 479 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 480 m_settype(bp, MB_NATOUT); 481 /* Ensure there's a bit of extra buffer for the NAT code... */ 482 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 483 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 484 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 485 486 return bp; 487 } 488 489 static struct mbuf * 490 nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 491 u_short *proto) 492 { 493 static int gfrags; 494 int ret, len, nfrags; 495 struct mbuf **last; 496 char *fptr; 497 498 if (!bundle->NatEnabled || *proto != PROTO_IP) 499 return bp; 500 501 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 502 m_settype(bp, MB_NATIN); 503 /* Ensure there's a bit of extra buffer for the NAT code... */ 504 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 505 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 506 507 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 508 if (bp->m_len > MAX_MRU) { 509 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 510 (unsigned long)bp->m_len); 511 m_freem(bp); 512 return NULL; 513 } 514 515 switch (ret) { 516 case PKT_ALIAS_OK: 517 break; 518 519 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 520 /* Save the data for later */ 521 fptr = malloc(bp->m_len); 522 bp = mbuf_Read(bp, fptr, bp->m_len); 523 PacketAliasSaveFragment(fptr); 524 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 525 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 526 break; 527 528 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 529 /* Fetch all the saved fragments and chain them on the end of `bp' */ 530 last = &bp->m_nextpkt; 531 nfrags = 0; 532 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 533 nfrags++; 534 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 535 len = ntohs(((struct ip *)fptr)->ip_len); 536 *last = m_get(len, MB_NATIN); 537 memcpy(MBUF_CTOP(*last), fptr, len); 538 free(fptr); 539 last = &(*last)->m_nextpkt; 540 } 541 gfrags -= nfrags; 542 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 543 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 544 nfrags, gfrags); 545 break; 546 547 case PKT_ALIAS_IGNORED: 548 if (PacketAliasSetMode(0, 0) & PKT_ALIAS_DENY_INCOMING) { 549 log_Printf(LogTCPIP, "NAT engine denied data:\n"); 550 m_freem(bp); 551 bp = NULL; 552 } else if (log_IsKept(LogTCPIP)) { 553 log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 554 PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL, 555 NULL, NULL); 556 } 557 break; 558 559 default: 560 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 561 m_freem(bp); 562 bp = NULL; 563 break; 564 } 565 566 return bp; 567 } 568 569 struct layer natlayer = 570 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 571