Merge branch 'vendor/OPENSSL'
[dragonfly.git] / usr.sbin / ppp / nat_cmd.c
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: src/usr.sbin/ppp/nat_cmd.c,v 1.35.2.13 2002/09/01 02:12:29 brian Exp $
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/ip.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38
39 #include <stdarg.h>
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 };