nat_cmd.c revision 58285
1/*- 2 * The code in this file was written by Eivind Eklund <perhaps@yes.no>, 3 * who places it in the public domain without restriction. 4 * 5 * $FreeBSD: head/usr.sbin/ppp/nat_cmd.c 58285 2000-03-19 12:37:27Z brian $ 6 */ 7 8#include <sys/param.h> 9#include <netinet/in.h> 10#include <arpa/inet.h> 11#include <netdb.h> 12#include <netinet/in_systm.h> 13#include <netinet/in.h> 14#include <netinet/ip.h> 15#include <sys/un.h> 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20#include <termios.h> 21 22#ifdef LOCALNAT 23#include "alias.h" 24#else 25#include <alias.h> 26#endif 27 28#include "layer.h" 29#include "proto.h" 30#include "defs.h" 31#include "command.h" 32#include "log.h" 33#include "nat_cmd.h" 34#include "descriptor.h" 35#include "prompt.h" 36#include "timer.h" 37#include "fsm.h" 38#include "slcompress.h" 39#include "throughput.h" 40#include "iplist.h" 41#include "mbuf.h" 42#include "lqr.h" 43#include "hdlc.h" 44#include "ipcp.h" 45#include "lcp.h" 46#include "ccp.h" 47#include "link.h" 48#include "mp.h" 49#include "filter.h" 50#ifndef NORADIUS 51#include "radius.h" 52#endif 53#include "bundle.h" 54 55 56#define NAT_EXTRABUF (13) 57 58static int StrToAddr(const char *, struct in_addr *); 59static int StrToPortRange(const char *, u_short *, u_short *, const char *); 60static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 61 u_short *, const char *); 62 63static void 64lowhigh(u_short *a, u_short *b) 65{ 66 if (a > b) { 67 u_short c; 68 69 c = *b; 70 *b = *a; 71 *a = c; 72 } 73} 74 75int 76nat_RedirectPort(struct cmdargs const *arg) 77{ 78 if (!arg->bundle->NatEnabled) { 79 prompt_Printf(arg->prompt, "Alias not enabled\n"); 80 return 1; 81 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 82 char proto_constant; 83 const char *proto; 84 struct in_addr localaddr; 85 u_short hlocalport, llocalport; 86 struct in_addr aliasaddr; 87 u_short haliasport, laliasport; 88 struct in_addr remoteaddr; 89 u_short hremoteport, lremoteport; 90 struct alias_link *link; 91 int error; 92 93 proto = arg->argv[arg->argn]; 94 if (strcmp(proto, "tcp") == 0) { 95 proto_constant = IPPROTO_TCP; 96 } else if (strcmp(proto, "udp") == 0) { 97 proto_constant = IPPROTO_UDP; 98 } else { 99 prompt_Printf(arg->prompt, "port redirect: protocol must be" 100 " tcp or udp\n"); 101 return -1; 102 } 103 104 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 105 &hlocalport, proto); 106 if (error) { 107 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 108 return -1; 109 } 110 111 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 112 proto); 113 if (error) { 114 prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 115 return -1; 116 } 117 aliasaddr.s_addr = INADDR_ANY; 118 119 if (arg->argc == arg->argn + 4) { 120 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 121 &lremoteport, &hremoteport, proto); 122 if (error) { 123 prompt_Printf(arg->prompt, "nat port: error reading " 124 "remoteaddr:port\n"); 125 return -1; 126 } 127 } else { 128 remoteaddr.s_addr = INADDR_ANY; 129 lremoteport = hremoteport = 0; 130 } 131 132 lowhigh(&llocalport, &hlocalport); 133 lowhigh(&laliasport, &haliasport); 134 lowhigh(&lremoteport, &hremoteport); 135 136 if (haliasport - laliasport != hlocalport - llocalport) { 137 prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 138 "are not equal\n"); 139 return -1; 140 } 141 142 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 143 prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 144 "are not equal\n"); 145 return -1; 146 } 147 148 while (laliasport <= haliasport) { 149 link = PacketAliasRedirectPort(localaddr, htons(llocalport), 150 remoteaddr, htons(lremoteport), 151 aliasaddr, htons(laliasport), 152 proto_constant); 153 154 if (link == NULL) { 155 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 156 error); 157 return 1; 158 } 159 llocalport++; 160 laliasport++; 161 if (hremoteport) 162 lremoteport++; 163 } 164 165 return 0; 166 } 167 168 return -1; 169} 170 171 172int 173nat_RedirectAddr(struct cmdargs const *arg) 174{ 175 if (!arg->bundle->NatEnabled) { 176 prompt_Printf(arg->prompt, "nat not enabled\n"); 177 return 1; 178 } else if (arg->argc == arg->argn+2) { 179 int error; 180 struct in_addr localaddr, aliasaddr; 181 struct alias_link *link; 182 183 error = StrToAddr(arg->argv[arg->argn], &localaddr); 184 if (error) { 185 prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 186 return 1; 187 } 188 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 189 if (error) { 190 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 191 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 192 arg->cmd->syntax); 193 return 1; 194 } 195 link = PacketAliasRedirectAddr(localaddr, aliasaddr); 196 if (link == NULL) { 197 prompt_Printf(arg->prompt, "address redirect: packet aliasing" 198 " engine error\n"); 199 prompt_Printf(arg->prompt, "Usage: nat %s %s\n", arg->cmd->name, 200 arg->cmd->syntax); 201 } 202 } else 203 return -1; 204 205 return 0; 206} 207 208 209static int 210StrToAddr(const char *str, struct in_addr *addr) 211{ 212 struct hostent *hp; 213 214 if (inet_aton(str, addr)) 215 return 0; 216 217 hp = gethostbyname(str); 218 if (!hp) { 219 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 220 return -1; 221 } 222 *addr = *((struct in_addr *) hp->h_addr); 223 return 0; 224} 225 226 227static int 228StrToPort(const char *str, u_short *port, const char *proto) 229{ 230 struct servent *sp; 231 char *end; 232 233 *port = strtol(str, &end, 10); 234 if (*end != '\0') { 235 sp = getservbyname(str, proto); 236 if (sp == NULL) { 237 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 238 str, proto); 239 return -1; 240 } 241 *port = ntohs(sp->s_port); 242 } 243 244 return 0; 245} 246 247static int 248StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 249{ 250 char *minus; 251 int res; 252 253 minus = strchr(str, '-'); 254 if (minus) 255 *minus = '\0'; /* Cheat the const-ness ! */ 256 257 res = StrToPort(str, low, proto); 258 259 if (minus) 260 *minus = '-'; /* Cheat the const-ness ! */ 261 262 if (res == 0) { 263 if (minus) 264 res = StrToPort(minus + 1, high, proto); 265 else 266 *high = *low; 267 } 268 269 return res; 270} 271 272static int 273StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 274 u_short *high, const char *proto) 275{ 276 char *colon; 277 int res; 278 279 colon = strchr(str, ':'); 280 if (!colon) { 281 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 282 return -1; 283 } 284 285 *colon = '\0'; /* Cheat the const-ness ! */ 286 res = StrToAddr(str, addr); 287 *colon = ':'; /* Cheat the const-ness ! */ 288 if (res != 0) 289 return -1; 290 291 return StrToPortRange(colon + 1, low, high, proto); 292} 293 294int 295nat_ProxyRule(struct cmdargs const *arg) 296{ 297 char cmd[LINE_LEN]; 298 int f, pos; 299 size_t len; 300 301 if (arg->argn >= arg->argc) 302 return -1; 303 304 for (f = arg->argn, pos = 0; f < arg->argc; f++) { 305 len = strlen(arg->argv[f]); 306 if (sizeof cmd - pos < len + (f ? 1 : 0)) 307 break; 308 if (f) 309 cmd[pos++] = ' '; 310 strcpy(cmd + pos, arg->argv[f]); 311 pos += len; 312 } 313 314 return PacketAliasProxyRule(cmd); 315} 316 317int 318nat_Pptp(struct cmdargs const *arg) 319{ 320 struct in_addr addr; 321 322 if (arg->argc == arg->argn) { 323 addr.s_addr = INADDR_NONE; 324 PacketAliasPptp(addr); 325 return 0; 326 } 327 328 if (arg->argc != arg->argn + 1) 329 return -1; 330 331 addr = GetIpAddr(arg->argv[arg->argn]); 332 if (addr.s_addr == INADDR_NONE) { 333 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 334 return 1; 335 } 336 337 PacketAliasPptp(addr); 338 return 0; 339} 340 341static struct mbuf * 342nat_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, 343 int pri, u_short *proto) 344{ 345 if (!bundle->NatEnabled || *proto != PROTO_IP) 346 return bp; 347 348 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 349 m_settype(bp, MB_NATOUT); 350 /* Ensure there's a bit of extra buffer for the NAT code... */ 351 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 352 PacketAliasOut(MBUF_CTOP(bp), bp->m_len); 353 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 354 355 return bp; 356} 357 358static struct mbuf * 359nat_LayerPull(struct bundle *bundle, struct link *l, struct mbuf *bp, 360 u_short *proto) 361{ 362 static int gfrags; 363 struct ip *pip, *piip; 364 int ret, len, nfrags; 365 struct mbuf **last; 366 char *fptr; 367 368 if (!bundle->NatEnabled || *proto != PROTO_IP) 369 return bp; 370 371 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 372 m_settype(bp, MB_NATIN); 373 bp = m_pullup(bp); 374 pip = (struct ip *)MBUF_CTOP(bp); 375 piip = (struct ip *)((char *)pip + (pip->ip_hl << 2)); 376 377 if (pip->ip_p == IPPROTO_IGMP || 378 (pip->ip_p == IPPROTO_IPIP && IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) 379 return bp; 380 381 /* Ensure there's a bit of extra buffer for the NAT code... */ 382 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 383 ret = PacketAliasIn(MBUF_CTOP(bp), bp->m_len); 384 pip = (struct ip *)MBUF_CTOP(bp); 385 386 bp->m_len = ntohs(pip->ip_len); 387 if (bp->m_len > MAX_MRU) { 388 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 389 (unsigned long)bp->m_len); 390 m_freem(bp); 391 return NULL; 392 } 393 394 switch (ret) { 395 case PKT_ALIAS_OK: 396 break; 397 398 case PKT_ALIAS_UNRESOLVED_FRAGMENT: 399 /* Save the data for later */ 400 fptr = malloc(bp->m_len); 401 bp = mbuf_Read(bp, fptr, bp->m_len); 402 PacketAliasSaveFragment(fptr); 403 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 404 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 405 break; 406 407 case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 408 /* Fetch all the saved fragments and chain them on the end of `bp' */ 409 last = &bp->m_nextpkt; 410 nfrags = 0; 411 while ((fptr = PacketAliasGetFragment(MBUF_CTOP(bp))) != NULL) { 412 nfrags++; 413 PacketAliasFragmentIn(MBUF_CTOP(bp), fptr); 414 len = ntohs(((struct ip *)fptr)->ip_len); 415 *last = m_get(len, MB_NATIN); 416 memcpy(MBUF_CTOP(*last), fptr, len); 417 free(fptr); 418 last = &(*last)->m_nextpkt; 419 } 420 gfrags -= nfrags; 421 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 422 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 423 nfrags, gfrags); 424 break; 425 426 default: 427 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet....\n"); 428 m_freem(bp); 429 bp = NULL; 430 break; 431 } 432 433 return bp; 434} 435 436struct layer natlayer = 437 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 438