2 * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $Id: glue.c 12264 2013-04-27 20:21:06Z luigi $
29 * Userland functions missing in linux/Windows
42 /* dummy nat functions */
44 ipfw_show_nat(int ac, char **av)
46 fprintf(stderr, "%s unsupported\n", __FUNCTION__);
50 ipfw_config_nat(int ac, char **av)
52 fprintf(stderr, "%s unsupported\n", __FUNCTION__);
57 int optreset; /* missing in linux */
61 * not implemented in linux.
62 * taken from /usr/src/lib/libc/string/strlcpy.c
65 strlcpy(char *dst, const char *src, size_t siz)
71 /* Copy as many bytes as will fit */
72 if (n != 0 && --n != 0) {
74 if ((*d++ = *s++) == 0)
79 /* Not enough room in dst, add NUL and traverse rest of src */
82 *d = '\0'; /* NUL-terminate dst */
87 return(s - src - 1); /* count does not include NUL */
91 /* missing in linux and windows */
93 strtonum(const char *nptr, long long minval, long long maxval,
97 int errno_c = errno; /* save actual errno */
101 ret = strtol(nptr, (char **)errstr, 0);
103 ret = strtoll(nptr, (char **)errstr, 0);
105 /* We accept only a string that represent exactly a number (ie. start
106 * and end with a digit).
107 * FreeBSD version wants errstr==NULL if no error occurs, otherwise
108 * errstr should point to an error string.
109 * For our purspose, we implement only the invalid error, ranges
110 * error aren't checked
112 if (errno != 0 || nptr == *errstr || **errstr != '\0')
121 #if defined (_WIN32) || defined (EMULATE_SYSCTL)
122 //XXX missing prerequisites
123 #include <net/if.h> //openwrt
124 #include <netinet/ip.h> //openwrt
125 #include <netinet/ip_fw.h>
126 #include <netinet/ip_dummynet.h>
130 * set or get system information
131 * XXX lock acquisition/serialize calls
133 * we export this as sys/module/ipfw_mod/parameters/___
134 * This function get or/and set the value of the sysctl passed by
135 * the name parameter. If the old value is not desired,
136 * oldp and oldlenp should be set to NULL.
139 * I do not know how this works in FreeBSD in the case
140 * where there are no write permission on the sysctl var.
141 * We read the value and set return variables in any way
142 * but returns -1 on write failures, regardless the
145 * Since there is no information on types, in the following
146 * code we assume a length of 4 is a int.
148 * Returns 0 on success, -1 on errors.
151 sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
154 #if defined (_WIN32) || defined (EMULATE_SYSCTL)
156 * we embed the sysctl request in the usual sockopt mechanics.
157 * the sockopt buffer il filled with a dn_id with IP_DUMMYNET3
158 * command, and the special DN_SYSCTL_GET and DN_SYSCTL_SET
160 * the syntax of this function is fully compatible with
161 * POSIX sysctlby name:
162 * if newp and newlen are != 0 => this is a set
163 * else if oldp and oldlen are != 0 => this is a get
164 * to avoid too much overhead in the module, the whole
165 * sysctltable is returned, and the parsing is done in userland,
166 * a probe request is done to retrieve the size needed to
167 * transfer the table, before the real request
168 * if both old and new params = 0 => this is a print
169 * this is a special request, done only by main()
170 * to implement the extension './ipfw sysctl',
171 * a command that bypasses the normal getopt, and that
172 * is available on those platforms that use this
174 * in this case, a negative oldlen signals that *oldp
175 * is actually a FILE* to print somewhere else than stdout
181 struct sysctlhead* entry;
186 if((oldlenp != NULL) && (*oldlenp < 0))
190 if(newp != NULL && newlen != 0)
193 l = sizeof(struct dn_id) + sizeof(struct sysctlhead) + strlen(name)+1 + newlen;
198 oid->type = DN_SYSCTL_SET;
199 oid->id = DN_API_VERSION;
201 entry = (struct sysctlhead*)(oid+1);
202 pdata = (char*)(entry+1);
203 pstring = pdata + newlen;
205 entry->blocklen = ((sizeof(struct sysctlhead) + strlen(name)+1 + newlen) + 3) & ~3;
206 entry->namelen = strlen(name)+1;
208 entry->datalen = newlen;
210 bcopy(newp, pdata, newlen);
211 bcopy(name, pstring, strlen(name)+1);
213 ret = do_cmd(IP_DUMMYNET3, oid, (uintptr_t)l);
219 //this is a get or a print
220 l = sizeof(struct dn_id);
225 oid->type = DN_SYSCTL_GET;
226 oid->id = DN_API_VERSION;
228 ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
238 oid->type = DN_SYSCTL_GET;
239 oid->id = DN_API_VERSION;
241 ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l);
245 entry = (struct sysctlhead*)(oid+1);
246 while(entry->blocklen != 0)
248 pdata = (char*)(entry+1);
249 pstring = pdata+entry->datalen;
251 //time to check if this is a get or a print
252 if(name != NULL && oldp != NULL && *oldlenp > 0)
255 if(strcmp(name,pstring) == 0)
257 //match found, sanity chech on len
258 if(*oldlenp < entry->datalen)
260 printf("%s error: buffer too small\n",__FUNCTION__);
263 *oldlenp = entry->datalen;
264 bcopy(pdata, oldp, *oldlenp);
273 if ( (strncmp(pstring,name,strlen(name)) == 0) && ( pstring[strlen(name)]=='\0' || pstring[strlen(name)]=='.' ) )
278 fprintf(fp, "%s: ",pstring);
279 switch( entry->flags >> 2 )
281 case SYSCTLTYPE_LONG:
282 fprintf(fp, "%li ", *(long*)(pdata));
284 case SYSCTLTYPE_UINT:
285 fprintf(fp, "%u ", *(unsigned int*)(pdata));
287 case SYSCTLTYPE_ULONG:
288 fprintf(fp, "%lu ", *(unsigned long*)(pdata));
292 fprintf(fp, "%i ", *(int*)(pdata));
294 if( (entry->flags & 0x00000003) == CTLFLAG_RD )
295 fprintf(fp, "\t(read only)\n");
300 entry = (struct sysctlhead*)((unsigned char*)entry + entry->blocklen);
305 //fallback for invalid options
308 #else /* __linux__ */
310 char *basename = "/sys/module/ipfw_mod/parameters/";
311 char filename[256]; /* full filename */
313 int ret = 0; /* return value */
316 if (name == NULL) /* XXX set errno */
319 /* locate the filename */
320 varp = strrchr(name, '.');
321 if (varp == NULL) /* XXX set errno */
324 snprintf(filename, sizeof(filename), "%s%s", basename, varp+1);
327 * XXX we could open the file here, in rw mode
328 * but need to check if a file have write
332 /* check parameters */
333 if (oldp && oldlenp) { /* read mode */
334 fp = fopen(filename, "r");
336 fprintf(stderr, "%s fopen error reading filename %s\n", __FUNCTION__, filename);
339 if (fscanf(fp, "%ld", &d) != 1) {
341 } else if (*oldlenp == sizeof(int)) {
343 memcpy(oldp, &dst, *oldlenp);
344 } else if (*oldlenp == sizeof(long)) {
345 memcpy(oldp, &d, *oldlenp);
347 fprintf(stderr, "unknown paramerer len %d\n",
353 if (newp && newlen) { /* write */
354 fp = fopen(filename, "w");
356 fprintf(stderr, "%s fopen error writing filename %s\n", __FUNCTION__, filename);
359 if (newlen == sizeof(int)) {
360 if (fprintf(fp, "%d", *(int *)newp) < 1)
362 } else if (newlen == sizeof(long)) {
363 if (fprintf(fp, "%ld", *(long *)newp) < 1)
366 fprintf(stderr, "unknown paramerer len %d\n",
374 #endif /* __linux__ */
379 * On windows, set/getsockopt are mapped to DeviceIoControl()
382 wnd_setsockopt(int s, int level, int sopt_name, const void *optval,
385 size_t len = sizeof (struct sockopt) + optlen;
386 struct sockopt *sock;
389 HANDLE _dev_h = (HANDLE)s;
391 /* allocate a data structure for communication */
396 sock->sopt_dir = SOPT_SET;
397 sock->sopt_name = sopt_name;
398 sock->sopt_valsize = optlen;
399 sock->sopt_val = (void *)(sock+1);
401 memcpy(sock->sopt_val, optval, optlen);
402 result = DeviceIoControl (_dev_h, IP_FW_SETSOCKOPT, sock, len,
406 return (result ? 0 : -1);
410 wnd_getsockopt(int s, int level, int sopt_name, void *optval,
413 size_t len = sizeof (struct sockopt) + *optlen;
414 struct sockopt *sock;
417 HANDLE _dev_h = (HANDLE)s;
423 sock->sopt_dir = SOPT_GET;
424 sock->sopt_name = sopt_name;
425 sock->sopt_valsize = *optlen;
426 sock->sopt_val = (void *)(sock+1);
428 memcpy (sock->sopt_val, optval, *optlen);
430 result = DeviceIoControl (_dev_h, IP_FW_GETSOCKOPT, sock, len,
431 sock, len, &n, NULL);
432 //printf("len = %i, returned = %u, valsize = %i\n",len,n,sock->sopt_valsize);
433 *optlen = sock->sopt_valsize;
434 memcpy (optval, sock->sopt_val, *optlen);
436 return (result ? 0 : -1);
440 my_socket(int domain, int ty, int proto)
442 TCHAR *pcCommPort = TEXT("\\\\.\\Ipfw");
443 HANDLE _dev_h = INVALID_HANDLE_VALUE;
445 /* Special Handling For Accessing Device On Windows 2000 Terminal Server
446 See Microsoft KB Article 259131 */
447 if (_dev_h == INVALID_HANDLE_VALUE) {
448 _dev_h = CreateFile (pcCommPort,
449 GENERIC_READ | GENERIC_WRITE,
451 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
453 if (_dev_h == INVALID_HANDLE_VALUE) {
454 printf("%s failed %u, cannot talk to kernel module\n",
455 __FUNCTION__, (unsigned)GetLastError());
461 struct hostent* gethostbyname2(const char *name, int af)
463 return gethostbyname(name);
466 struct ether_addr* ether_aton(const char *a)
468 fprintf(stderr, "%s empty\n", __FUNCTION__);
473 int opterr = 1, /* if error message should be printed */
474 optind = 1, /* index into parent argv vector */
475 optopt, /* character checked for validity */
476 optreset; /* reset getopt */
477 char *optarg; /* argument associated with option */
479 #define BADCH (int)'?'
480 #define BADARG (int)':'
483 #define PROGNAME "ipfw"
486 * Parse argc/argv argument vector.
489 getopt(nargc, nargv, ostr)
491 char * const nargv[];
494 static char *place = EMSG; /* option letter processing */
495 char *oli; /* option letter list index */
497 if (optreset || *place == 0) { /* update scanning pointer */
499 place = nargv[optind];
500 if (optind >= nargc || *place++ != '-') {
501 /* Argument is absent or is not an option */
506 if (optopt == '-' && *place == 0) {
507 /* "--" => end of options */
513 /* Solitary '-', treat as a '-' option
514 if the program (eg su) is looking for it. */
516 if (strchr(ostr, '-') == NULL)
523 /* See if option letter is one the caller wanted... */
524 if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
527 if (opterr && *ostr != ':')
528 (void)fprintf(stderr,
529 "%s: illegal option -- %c\n", PROGNAME,
534 /* Does this option need an argument? */
536 /* don't need argument */
541 /* Option-argument is either the rest of this argument or the
542 entire next argument. */
545 else if (nargc > ++optind)
546 optarg = nargv[optind];
548 /* option-argument absent */
553 (void)fprintf(stderr,
554 "%s: option requires an argument -- %c\n",
561 return (optopt); /* return option letter */
564 //static FILE *err_file = stderr;
566 verrx(int ex, int eval, const char *fmt, va_list ap)
568 fprintf(stderr, "%s: ", PROGNAME);
570 vfprintf(stderr, fmt, ap);
571 fprintf(stderr, "\n");
576 errx(int eval, const char *fmt, ...)
580 verrx(1, eval, fmt, ap);
585 warnx(const char *fmt, ...)
589 verrx(0, 0, fmt, ap);
594 strsep(char **stringp, const char *delim)
601 if ((s = *stringp) == NULL)
607 if ((sc = *spanp++) == c) {
621 tolower(unsigned char c)
623 return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
626 static int isdigit(unsigned char c)
628 return (c >= '0' && c <= '9');
631 static int isxdigit(unsigned char c)
633 return (strchr("0123456789ABCDEFabcdef", c) ? 1 : 0);
636 static int isspace(unsigned char c)
638 return (strchr(" \t\n\r", c) ? 1 : 0);
641 static int isascii(unsigned char c)
646 static int islower(unsigned char c)
648 return (c >= 'a' && c <= 'z');
652 strcasecmp(const char *s1, const char *s2)
655 *us1 = (const unsigned char *)s1,
656 *us2 = (const unsigned char *)s2;
658 while (tolower(*us1) == tolower(*us2++))
661 return (tolower(*us1) - tolower(*--us2));
665 strtoimax(const char * restrict nptr, char ** restrict endptr, int base)
667 return strtol(nptr, endptr,base);
675 #define NS_INADDRSZ 128
678 inet_pton(int af, const char *src, void *dst)
680 static const char digits[] = "0123456789";
681 int saw_digit, octets, ch;
682 u_char tmp[NS_INADDRSZ], *tp;
692 while ((ch = *src++) != '\0') {
695 if ((pch = strchr(digits, ch)) != NULL) {
696 u_int new = *tp * 10 + (pch - digits);
698 if (saw_digit && *tp == 0)
708 } else if (ch == '.' && saw_digit) {
718 memcpy(dst, tmp, NS_INADDRSZ);
723 inet_ntop(int af, const void *_src, char *dst, socklen_t size)
725 static const char fmt[] = "%u.%u.%u.%u";
726 char tmp[sizeof "255.255.255.255"];
727 const u_char *src = _src;
734 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
735 if (l <= 0 || (socklen_t) l >= size) {
739 strlcpy(dst, tmp, size);
744 * Check whether "cp" is a valid ascii representation
745 * of an Internet address and convert to a binary address.
746 * Returns 1 if the address is valid, 0 if not.
747 * This replaces inet_addr, the return value from which
748 * cannot distinguish between failure and a local broadcast address.
751 inet_aton(const char *cp, struct in_addr *addr) {
756 u_int8_t *pp = parts;
762 * Collect number up to ``.''.
763 * Values are specified as for C:
764 * 0x=hex, 0=octal, isdigit=decimal.
766 if (!isdigit((unsigned char)c))
768 val = 0; base = 10; digit = 0;
771 if (c == 'x' || c == 'X')
772 base = 16, c = *++cp;
779 if (isascii(c) && isdigit((unsigned char)c)) {
780 if (base == 8 && (c == '8' || c == '9'))
782 val = (val * base) + (c - '0');
785 } else if (base == 16 && isascii(c) &&
786 isxdigit((unsigned char)c)) {
788 (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
798 * a.b.c (with c treated as 16 bits)
799 * a.b (with b treated as 24 bits)
801 if (pp >= parts + 3 || val > 0xffU)
809 * Check for trailing characters.
811 if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c)))
814 * Did we get a valid digit?
819 * Concoct the address according to
820 * the number of parts specified.
824 case 1: /*%< a -- 32 bits */
827 case 2: /*%< a.b -- 8.24 bits */
830 val |= parts[0] << 24;
833 case 3: /*%< a.b.c -- 8.8.16 bits */
836 val |= (parts[0] << 24) | (parts[1] << 16);
839 case 4: /*%< a.b.c.d -- 8.8.8.8 bits */
842 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
846 addr->s_addr = htonl(val);