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 5881 2010-03-25 14:29:48Z svn_panicucci $
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 lenght 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 = (unsigned 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 = (unsigned 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);
340 if (fscanf(fp, "%d", &d) == 1)
341 memcpy(oldp, &d, *oldlenp);
348 if (newp && newlen) { /* write */
349 fp = fopen(filename, "w");
351 fprintf(stderr, "%s fopen error writing filename %s\n", __FUNCTION__, filename);
355 if (fprintf(fp, "%d", *(int*)newp) < 1)
363 #endif /* __linux__ */
368 * On windows, set/getsockopt are mapped to DeviceIoControl()
371 wnd_setsockopt(int s, int level, int sopt_name, const void *optval,
374 size_t len = sizeof (struct sockopt) + optlen;
375 struct sockopt *sock;
378 HANDLE _dev_h = (HANDLE)s;
380 /* allocate a data structure for communication */
385 sock->sopt_dir = SOPT_SET;
386 sock->sopt_name = sopt_name;
387 sock->sopt_valsize = optlen;
388 sock->sopt_val = (void *)(sock+1);
390 memcpy(sock->sopt_val, optval, optlen);
391 result = DeviceIoControl (_dev_h, IP_FW_SETSOCKOPT, sock, len,
395 return (result ? 0 : -1);
399 wnd_getsockopt(int s, int level, int sopt_name, void *optval,
402 size_t len = sizeof (struct sockopt) + *optlen;
403 struct sockopt *sock;
406 HANDLE _dev_h = (HANDLE)s;
412 sock->sopt_dir = SOPT_GET;
413 sock->sopt_name = sopt_name;
414 sock->sopt_valsize = *optlen;
415 sock->sopt_val = (void *)(sock+1);
417 memcpy (sock->sopt_val, optval, *optlen);
419 result = DeviceIoControl (_dev_h, IP_FW_GETSOCKOPT, sock, len,
420 sock, len, &n, NULL);
421 //printf("len = %i, returned = %u, valsize = %i\n",len,n,sock->sopt_valsize);
422 *optlen = sock->sopt_valsize;
423 memcpy (optval, sock->sopt_val, *optlen);
425 return (result ? 0 : -1);
429 my_socket(int domain, int ty, int proto)
431 TCHAR *pcCommPort = TEXT("\\\\.\\Ipfw");
432 HANDLE _dev_h = INVALID_HANDLE_VALUE;
434 /* Special Handling For Accessing Device On Windows 2000 Terminal Server
435 See Microsoft KB Article 259131 */
436 if (_dev_h == INVALID_HANDLE_VALUE) {
437 _dev_h = CreateFile (pcCommPort,
438 GENERIC_READ | GENERIC_WRITE,
440 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
442 if (_dev_h == INVALID_HANDLE_VALUE) {
443 printf("%s failed %u, cannot talk to kernel module\n",
444 __FUNCTION__, (unsigned)GetLastError());
450 struct hostent* gethostbyname2(const char *name, int af)
452 return gethostbyname(name);
455 struct ether_addr* ether_aton(const char *a)
457 fprintf(stderr, "%s empty\n", __FUNCTION__);
462 int opterr = 1, /* if error message should be printed */
463 optind = 1, /* index into parent argv vector */
464 optopt, /* character checked for validity */
465 optreset; /* reset getopt */
466 char *optarg; /* argument associated with option */
468 #define BADCH (int)'?'
469 #define BADARG (int)':'
472 #define PROGNAME "ipfw"
475 * Parse argc/argv argument vector.
478 getopt(nargc, nargv, ostr)
480 char * const nargv[];
483 static char *place = EMSG; /* option letter processing */
484 char *oli; /* option letter list index */
486 if (optreset || *place == 0) { /* update scanning pointer */
488 place = nargv[optind];
489 if (optind >= nargc || *place++ != '-') {
490 /* Argument is absent or is not an option */
495 if (optopt == '-' && *place == 0) {
496 /* "--" => end of options */
502 /* Solitary '-', treat as a '-' option
503 if the program (eg su) is looking for it. */
505 if (strchr(ostr, '-') == NULL)
512 /* See if option letter is one the caller wanted... */
513 if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
516 if (opterr && *ostr != ':')
517 (void)fprintf(stderr,
518 "%s: illegal option -- %c\n", PROGNAME,
523 /* Does this option need an argument? */
525 /* don't need argument */
530 /* Option-argument is either the rest of this argument or the
531 entire next argument. */
534 else if (nargc > ++optind)
535 optarg = nargv[optind];
537 /* option-argument absent */
542 (void)fprintf(stderr,
543 "%s: option requires an argument -- %c\n",
550 return (optopt); /* return option letter */
553 //static FILE *err_file = stderr;
555 verrx(int ex, int eval, const char *fmt, va_list ap)
557 fprintf(stderr, "%s: ", PROGNAME);
559 vfprintf(stderr, fmt, ap);
560 fprintf(stderr, "\n");
565 errx(int eval, const char *fmt, ...)
569 verrx(1, eval, fmt, ap);
574 warnx(const char *fmt, ...)
578 verrx(0, 0, fmt, ap);
583 strsep(char **stringp, const char *delim)
590 if ((s = *stringp) == NULL)
596 if ((sc = *spanp++) == c) {
610 tolower(unsigned char c)
612 return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
615 static int isdigit(unsigned char c)
617 return (c >= '0' && c <= '9');
620 static int isxdigit(unsigned char c)
622 return (index("0123456789ABCDEFabcdef", c) ? 1 : 0);
625 static int isspace(unsigned char c)
627 return (index(" \t\n\r", c) ? 1 : 0);
630 static int isascii(unsigned char c)
635 static int islower(unsigned char c)
637 return (c >= 'a' && c <= 'z');
641 strcasecmp(const char *s1, const char *s2)
644 *us1 = (const unsigned char *)s1,
645 *us2 = (const unsigned char *)s2;
647 while (tolower(*us1) == tolower(*us2++))
650 return (tolower(*us1) - tolower(*--us2));
654 strtoimax(const char * restrict nptr, char ** restrict endptr, int base)
656 return strtol(nptr, endptr,base);
664 #define NS_INADDRSZ 128
667 inet_pton(int af, const char *src, void *dst)
669 static const char digits[] = "0123456789";
670 int saw_digit, octets, ch;
671 u_char tmp[NS_INADDRSZ], *tp;
681 while ((ch = *src++) != '\0') {
684 if ((pch = strchr(digits, ch)) != NULL) {
685 u_int new = *tp * 10 + (pch - digits);
687 if (saw_digit && *tp == 0)
697 } else if (ch == '.' && saw_digit) {
707 memcpy(dst, tmp, NS_INADDRSZ);
712 inet_ntop(int af, const void *_src, char *dst, socklen_t size)
714 static const char fmt[] = "%u.%u.%u.%u";
715 char tmp[sizeof "255.255.255.255"];
716 const u_char *src = _src;
723 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
724 if (l <= 0 || (socklen_t) l >= size) {
728 strlcpy(dst, tmp, size);
733 * Check whether "cp" is a valid ascii representation
734 * of an Internet address and convert to a binary address.
735 * Returns 1 if the address is valid, 0 if not.
736 * This replaces inet_addr, the return value from which
737 * cannot distinguish between failure and a local broadcast address.
740 inet_aton(const char *cp, struct in_addr *addr) {
745 u_int8_t *pp = parts;
751 * Collect number up to ``.''.
752 * Values are specified as for C:
753 * 0x=hex, 0=octal, isdigit=decimal.
755 if (!isdigit((unsigned char)c))
757 val = 0; base = 10; digit = 0;
760 if (c == 'x' || c == 'X')
761 base = 16, c = *++cp;
768 if (isascii(c) && isdigit((unsigned char)c)) {
769 if (base == 8 && (c == '8' || c == '9'))
771 val = (val * base) + (c - '0');
774 } else if (base == 16 && isascii(c) &&
775 isxdigit((unsigned char)c)) {
777 (c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
787 * a.b.c (with c treated as 16 bits)
788 * a.b (with b treated as 24 bits)
790 if (pp >= parts + 3 || val > 0xffU)
798 * Check for trailing characters.
800 if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c)))
803 * Did we get a valid digit?
808 * Concoct the address according to
809 * the number of parts specified.
813 case 1: /*%< a -- 32 bits */
816 case 2: /*%< a.b -- 8.24 bits */
819 val |= parts[0] << 24;
822 case 3: /*%< a.b.c -- 8.8.16 bits */
825 val |= (parts[0] << 24) | (parts[1] << 16);
828 case 4: /*%< a.b.c.d -- 8.8.8.8 bits */
831 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
835 addr->s_addr = htonl(val);