nat_cmd.c revision 77690
1285SN/A/*- 2462SN/A * Copyright (c) 2001 Charles Mott <cmott@scientech.com> 3285SN/A * Brian Somers <brian@Awfulhak.org> 4285SN/A * All rights reserved. 5285SN/A * 6285SN/A * Redistribution and use in source and binary forms, with or without 7285SN/A * modification, are permitted provided that the following conditions 8285SN/A * are met: 9285SN/A * 1. Redistributions of source code must retain the above copyright 10285SN/A * notice, this list of conditions and the following disclaimer. 11285SN/A * 2. Redistributions in binary form must reproduce the above copyright 12285SN/A * notice, this list of conditions and the following disclaimer in the 13285SN/A * documentation and/or other materials provided with the distribution. 14285SN/A * 15285SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16285SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17285SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18285SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19285SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20285SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21285SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22285SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23285SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24285SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25285SN/A * SUCH DAMAGE. 26285SN/A * 27285SN/A * $FreeBSD: head/usr.sbin/ppp/nat_cmd.c 77690 2001-06-04 14:38:29Z brian $ 28285SN/A */ 29285SN/A 30285SN/A#include <sys/param.h> 31285SN/A#include <netinet/in.h> 32285SN/A#include <arpa/inet.h> 33285SN/A#include <netdb.h> 34285SN/A#include <netinet/in_systm.h> 35285SN/A#include <netinet/in.h> 36285SN/A#include <netinet/ip.h> 37285SN/A#include <sys/un.h> 38285SN/A 39285SN/A#include <stdio.h> 40285SN/A#include <stdlib.h> 41285SN/A#include <string.h> 42285SN/A#include <termios.h> 43285SN/A 44285SN/A#ifdef LOCALNAT 45285SN/A#include "alias.h" 46285SN/A#else 47285SN/A#include <alias.h> 48285SN/A#endif 49285SN/A 50285SN/A#include "layer.h" 51285SN/A#include "proto.h" 52285SN/A#include "defs.h" 53285SN/A#include "command.h" 54285SN/A#include "log.h" 55285SN/A#include "nat_cmd.h" 56285SN/A#include "descriptor.h" 57285SN/A#include "prompt.h" 58285SN/A#include "timer.h" 59285SN/A#include "fsm.h" 60285SN/A#include "slcompress.h" 61285SN/A#include "throughput.h" 62285SN/A#include "iplist.h" 63285SN/A#include "mbuf.h" 64285SN/A#include "lqr.h" 65285SN/A#include "hdlc.h" 66285SN/A#include "ipcp.h" 67285SN/A#include "lcp.h" 68285SN/A#include "ccp.h" 69285SN/A#include "link.h" 70285SN/A#include "mp.h" 71285SN/A#include "filter.h" 72285SN/A#ifndef NORADIUS 73285SN/A#include "radius.h" 74285SN/A#endif 75285SN/A#include "ip.h" 76285SN/A#include "bundle.h" 77285SN/A 78285SN/A 79285SN/A#define NAT_EXTRABUF (13) 80285SN/A 81285SN/Astatic int StrToAddr(const char *, struct in_addr *); 82285SN/Astatic int StrToPortRange(const char *, u_short *, u_short *, const char *); 83285SN/Astatic int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 84285SN/A u_short *, const char *); 85285SN/A 86285SN/Astatic void 87285SN/Alowhigh(u_short *a, u_short *b) 88285SN/A{ 89285SN/A if (a > b) { 90285SN/A u_short c; 91367SN/A 92285SN/A c = *b; 93285SN/A *b = *a; 94285SN/A *a = c; 95285SN/A } 96285SN/A} 97285SN/A 98285SN/Aint 99285SN/Anat_RedirectPort(struct cmdargs const *arg) 100285SN/A{ 101285SN/A if (!arg->bundle->NatEnabled) { 102285SN/A prompt_Printf(arg->prompt, "Alias not enabled\n"); 103285SN/A return 1; 104285SN/A } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 105285SN/A char proto_constant; 106285SN/A const char *proto; 107285SN/A struct in_addr localaddr; 108285SN/A u_short hlocalport, llocalport; 109285SN/A struct in_addr aliasaddr; 110285SN/A u_short haliasport, laliasport; 111285SN/A struct in_addr remoteaddr; 112285SN/A u_short hremoteport, lremoteport; 113285SN/A struct alias_link *link; 114285SN/A int error; 115285SN/A 116285SN/A proto = arg->argv[arg->argn]; 117285SN/A if (strcmp(proto, "tcp") == 0) { 118285SN/A proto_constant = IPPROTO_TCP; 119285SN/A } else if (strcmp(proto, "udp") == 0) { 120285SN/A proto_constant = IPPROTO_UDP; 121285SN/A } else { 122285SN/A prompt_Printf(arg->prompt, "port redirect: protocol must be" 123285SN/A " tcp or udp\n"); 124285SN/A return -1; 125285SN/A } 126285SN/A 127285SN/A error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 128285SN/A &hlocalport, proto); 129285SN/A if (error) { 130285SN/A prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 131285SN/A return -1; 132285SN/A } 133285SN/A 134285SN/A error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 135285SN/A proto); 136285SN/A if (error) { 137285SN/A prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 138285SN/A return -1; 139285SN/A } 140285SN/A aliasaddr.s_addr = INADDR_ANY; 141285SN/A 142285SN/A if (arg->argc == arg->argn + 4) { 143285SN/A error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 144285SN/A &lremoteport, &hremoteport, proto); 145285SN/A if (error) { 146285SN/A prompt_Printf(arg->prompt, "nat port: error reading " 147285SN/A "remoteaddr:port\n"); 148285SN/A return -1; 149285SN/A } 150285SN/A } else { 151285SN/A remoteaddr.s_addr = INADDR_ANY; 152285SN/A lremoteport = hremoteport = 0; 153285SN/A } 154285SN/A 155285SN/A lowhigh(&llocalport, &hlocalport); 156285SN/A lowhigh(&laliasport, &haliasport); 157285SN/A lowhigh(&lremoteport, &hremoteport); 158285SN/A 159285SN/A if (haliasport - laliasport != hlocalport - llocalport) { 160285SN/A prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 161285SN/A "are not equal\n"); 162285SN/A return -1; 163285SN/A } 164285SN/A 165285SN/A if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 166285SN/A prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 167285SN/A "are not equal\n"); 168285SN/A return -1; 169285SN/A } 170285SN/A 171285SN/A while (laliasport <= haliasport) { 172285SN/A link = PacketAliasRedirectPort(localaddr, htons(llocalport), 173285SN/A remoteaddr, htons(lremoteport), 174285SN/A aliasaddr, htons(laliasport), 175285SN/A proto_constant); 176285SN/A 177285SN/A if (link == NULL) { 178285SN/A prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 179285SN/A error); 180285SN/A return 1; 181285SN/A } 182285SN/A llocalport++; 183285SN/A laliasport++; 184285SN/A if (hremoteport) 185285SN/A lremoteport++; 186285SN/A } 187285SN/A 188285SN/A return 0; 189285SN/A } 190285SN/A 191285SN/A return -1; 192285SN/A} 193285SN/A 194285SN/A 195285SN/Aint 196285SN/Anat_RedirectAddr(struct cmdargs const *arg) 197285SN/A{ 198285SN/A if (!arg->bundle->NatEnabled) { 199285SN/A prompt_Printf(arg->prompt, "nat not enabled\n"); 200285SN/A return 1; 201285SN/A } else if (arg->argc == arg->argn+2) { 202285SN/A int error; 203285SN/A struct in_addr localaddr, aliasaddr; 204285SN/A struct alias_link *link; 205285SN/A 206285SN/A error = StrToAddr(arg->argv[arg->argn], &localaddr); 207285SN/A if (error) { 208285SN/A prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 209285SN/A return 1; 210285SN/A } 211285SN/A error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 212285SN/A if (error) { 213285SN/A prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 214285SN/A prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 215285SN/A arg->cmd->syntax); 216285SN/A return 1; 217285SN/A } 218285SN/A link = PacketAliasRedirectAddr(localaddr, aliasaddr); 219285SN/A if (link == NULL) { 220285SN/A prompt_Printf(arg->prompt, "address redirect: packet aliasing" 221285SN/A " engine error\n"); 222285SN/A prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 223285SN/A arg->cmd->syntax); 224285SN/A } 225285SN/A } else 226285SN/A return -1; 227285SN/A 228285SN/A return 0; 229285SN/A} 230285SN/A 231285SN/A 232285SN/Astatic int 233285SN/AStrToAddr(const char *str, struct in_addr *addr) 234285SN/A{ 235285SN/A struct hostent *hp; 236285SN/A 237285SN/A if (inet_aton(str, addr)) 238285SN/A return 0; 239285SN/A 240285SN/A hp = gethostbyname(str); 241285SN/A if (!hp) { 242285SN/A log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 243285SN/A return -1; 244285SN/A } 245285SN/A *addr = *((struct in_addr *) hp->h_addr); 246285SN/A return 0; 247285SN/A} 248285SN/A 249285SN/A 250285SN/Astatic int 251285SN/AStrToPort(const char *str, u_short *port, const char *proto) 252285SN/A{ 253285SN/A struct servent *sp; 254285SN/A char *end; 255285SN/A 256285SN/A *port = strtol(str, &end, 10); 257285SN/A if (*end != '\0') { 258285SN/A sp = getservbyname(str, proto); 259285SN/A if (sp == NULL) { 260285SN/A log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 261285SN/A str, proto); 262285SN/A return -1; 263285SN/A } 264285SN/A *port = ntohs(sp->s_port); 265285SN/A } 266285SN/A 267285SN/A return 0; 268285SN/A} 269285SN/A 270285SN/Astatic int 271285SN/AStrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 272285SN/A{ 273285SN/A char *minus; 274285SN/A int res; 275285SN/A 276285SN/A minus = strchr(str, '-'); 277285SN/A if (minus) 278285SN/A *minus = '\0'; /* Cheat the const-ness ! */ 279285SN/A 280285SN/A res = StrToPort(str, low, proto); 281285SN/A 282285SN/A if (minus) 283285SN/A *minus = '-'; /* Cheat the const-ness ! */ 284285SN/A 285285SN/A if (res == 0) { 286285SN/A if (minus) 287285SN/A res = StrToPort(minus + 1, high, proto); 288285SN/A else 289285SN/A *high = *low; 290285SN/A } 291285SN/A 292285SN/A return res; 293285SN/A} 294285SN/A 295285SN/Astatic int 296285SN/AStrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 297285SN/A u_short *high, const char *proto) 298285SN/A{ 299285SN/A char *colon; 300285SN/A int res; 301285SN/A 302285SN/A colon = strchr(str, ':'); 303285SN/A if (!colon) { 304285SN/A log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 305285SN/A return -1; 306285SN/A } 307285SN/A 308285SN/A *colon = '\0'; /* Cheat the const-ness ! */ 309285SN/A res = StrToAddr(str, addr); 310285SN/A *colon = ':'; /* Cheat the const-ness ! */ 311285SN/A if (res != 0) 312285SN/A return -1; 313285SN/A 314285SN/A return StrToPortRange(colon + 1, low, high, proto); 315285SN/A} 316285SN/A 317285SN/Aint 318285SN/Anat_ProxyRule(struct cmdargs const *arg) 319285SN/A{ 320285SN/A char cmd[LINE_LEN]; 321285SN/A int f, pos; 322285SN/A size_t len; 323285SN/A 324285SN/A if (arg->argn >= arg->argc) 325285SN/A return -1; 326285SN/A 327285SN/A for (f = arg->argn, pos = 0; f < arg->argc; f++) { 328285SN/A len = strlen(arg->argv[f]); 329285SN/A if (sizeof cmd - pos < len + (len ? 1 : 0)) 330285SN/A break; 331285SN/A if (len) 332285SN/A cmd[pos++] = ' '; 333285SN/A strcpy(cmd + pos, arg->argv[f]); 334285SN/A pos += len; 335285SN/A } 336285SN/A 337285SN/A return PacketAliasProxyRule(cmd); 338285SN/A} 339285SN/A 340285SN/Aint 341285SN/Anat_SetTarget(struct cmdargs const *arg) 342285SN/A{ 343285SN/A struct in_addr addr; 344285SN/A 345285SN/A if (arg->argc == arg->argn) { 346285SN/A addr.s_addr = INADDR_ANY; 347285SN/A PacketAliasSetTarget(addr); 348285SN/A return 0; 349285SN/A } 350285SN/A 351285SN/A if (arg->argc != arg->argn + 1) 352285SN/A return -1; 353285SN/A 354285SN/A if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { 355285SN/A addr.s_addr = INADDR_ANY; 356285SN/A PacketAliasSetTarget(addr); 357285SN/A return 0; 358285SN/A } 359285SN/A 360285SN/A addr = GetIpAddr(arg->argv[arg->argn]); 361285SN/A if (addr.s_addr == INADDR_NONE) { 362285SN/A log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 363285SN/A return 1; 364285SN/A } 365285SN/A 366285SN/A PacketAliasSetTarget(addr); 367285SN/A return 0; 368285SN/A} 369285SN/A 370285SN/Astatic struct mbuf * 371285SN/Anat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 372285SN/A int pri, u_short *proto) 373285SN/A{ 374285SN/A if (!bundle->NatEnabled || *proto != PROTO_IP) 375285SN/A return bp; 376285SN/A 377285SN/A log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 378285SN/A m_settype(bp, MB_NATOUT); 379285SN/A /* Ensure there's a bit of extra buffer for the NAT code... */ 380285SN/A bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 381285SN/A PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 382285SN/A bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 383285SN/A 384285SN/A return bp; 385285SN/A} 386285SN/A 387285SN/Astatic struct mbuf * 388285SN/Anat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 389285SN/A u_short *proto) 390285SN/A{ 391285SN/A static int gfrags; 392285SN/A int ret, len, nfrags; 393285SN/A struct mbuf **last; 394285SN/A char *fptr; 395285SN/A 396285SN/A if (!bundle->NatEnabled || *proto != PROTO_IP) 397285SN/A return bp; 398285SN/A 399285SN/A log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 400285SN/A m_settype(bp, MB_NATIN); 401285SN/A /* Ensure there's a bit of extra buffer for the NAT code... */ 402285SN/A bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 403285SN/A ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 404285SN/A 405285SN/A bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 406285SN/A if (bp->m_len > MAX_MRU) { 407285SN/A log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 408285SN/A (unsigned long)bp->m_len); 409285SN/A m_freem(bp); 410285SN/A return NULL; 411285SN/A } 412285SN/A 413285SN/A switch (ret) { 414285SN/A case PKT_ALIAS_OK: 415285SN/A break; 416285SN/A 417285SN/A case PKT_ALIAS_UNRESOLVED_FRAGMENT: 418285SN/A /* Save the data for later */ 419285SN/A fptr = malloc(bp->m_len); 420285SN/A bp = mbuf_Read(bp, fptr, bp->m_len); 421285SN/A PacketAliasSaveFragment(fptr); 422285SN/A log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 423285SN/A (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 424285SN/A break; 425285SN/A 426285SN/A case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 427285SN/A /* Fetch all the saved fragments and chain them on the end of `bp' */ 428285SN/A last = &bp->m_nextpkt; 429285SN/A nfrags = 0; 430285SN/A while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 431285SN/A nfrags++; 432285SN/A PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 433285SN/A len = ntohs(((struct ip *)fptr)->ip_len); 434285SN/A *last = m_get(len, MB_NATIN); 435285SN/A memcpy(MBUF_CTOP(*last), fptr, len); 436285SN/A free(fptr); 437285SN/A last = &(*last)->m_nextpkt; 438285SN/A } 439285SN/A gfrags -= nfrags; 440367SN/A log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 441285SN/A "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 442285SN/A nfrags, gfrags); 443285SN/A break; 444285SN/A 445285SN/A case PKT_ALIAS_IGNORED: 446285SN/A if (PacketAliasSetMode(0, 0) & PKT_ALIAS_DENY_INCOMING) { 447285SN/A log_Printf(LogTCPIP, "NAT engine denied data:\n"); 448285SN/A m_freem(bp); 449285SN/A bp = NULL; 450285SN/A } else if (log_IsKept(LogTCPIP)) { 451285SN/A log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 452285SN/A PacketCheck(bundle, MBUF_CTOP(bp), bp->m_len, NULL, NULL, NULL); 453285SN/A } 454285SN/A break; 455285SN/A 456285SN/A default: 457285SN/A log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 458285SN/A m_freem(bp); 459285SN/A bp = NULL; 460285SN/A break; 461285SN/A } 462285SN/A 463285SN/A return bp; 464285SN/A} 465285SN/A 466285SN/Astruct layer natlayer = 467285SN/A { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 468285SN/A