X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ipfw%2Fglue.c;h=3ede52277c020bb66d0b210b97da2a01e96732f2;hb=40445faa1db58b90083115bc315d095e7eb2fe51;hp=e5876b9b11c823d4b466b474e6454f45d21b9079;hpb=31b969263c34f46f398eec33c0b0e95947842cda;p=ipfw.git diff --git a/ipfw/glue.c b/ipfw/glue.c index e5876b9..3ede522 100644 --- a/ipfw/glue.c +++ b/ipfw/glue.c @@ -24,15 +24,20 @@ */ /* - * $Id: glue.c 4469 2009-12-11 20:23:11Z marta $ + * $Id: glue.c 5881 2010-03-25 14:29:48Z svn_panicucci $ * - * Userland functions missing in linux + * Userland functions missing in linux/Windows */ #include #include #include +#ifdef _WIN32 +#include +#include +#endif /* _WIN32 */ + #ifndef HAVE_NAT /* dummy nat functions */ void @@ -52,7 +57,6 @@ ipfw_config_nat(int ac, char **av) int optreset; /* missing in linux */ #endif -#if defined( __linux__ ) || defined(_WIN32) /* * not implemented in linux. * taken from /usr/src/lib/libc/string/strlcpy.c @@ -89,9 +93,39 @@ long long int strtonum(const char *nptr, long long minval, long long maxval, const char **errstr) { - return strtoll(nptr, (char **)errstr, 0); + long long ret; + int errno_c = errno; /* save actual errno */ + + errno = 0; +#ifdef TCC + ret = strtol(nptr, (char **)errstr, 0); +#else + ret = strtoll(nptr, (char **)errstr, 0); +#endif + /* We accept only a string that represent exactly a number (ie. start + * and end with a digit). + * FreeBSD version wants errstr==NULL if no error occurs, otherwise + * errstr should point to an error string. + * For our purspose, we implement only the invalid error, ranges + * error aren't checked + */ + if (errno != 0 || nptr == *errstr || **errstr != '\0') + *errstr = "invalid"; + else { + *errstr = NULL; + errno = errno_c; + } + return ret; } +#if defined (_WIN32) || defined (EMULATE_SYSCTL) +//XXX missing prerequisites +#include //openwrt +#include //openwrt +#include +#include +#endif + /* * set or get system information * XXX lock acquisition/serialize calls @@ -117,6 +151,161 @@ int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { +#if defined (_WIN32) || defined (EMULATE_SYSCTL) + /* + * we embed the sysctl request in the usual sockopt mechanics. + * the sockopt buffer il filled with a dn_id with IP_DUMMYNET3 + * command, and the special DN_SYSCTL_GET and DN_SYSCTL_SET + * subcommands. + * the syntax of this function is fully compatible with + * POSIX sysctlby name: + * if newp and newlen are != 0 => this is a set + * else if oldp and oldlen are != 0 => this is a get + * to avoid too much overhead in the module, the whole + * sysctltable is returned, and the parsing is done in userland, + * a probe request is done to retrieve the size needed to + * transfer the table, before the real request + * if both old and new params = 0 => this is a print + * this is a special request, done only by main() + * to implement the extension './ipfw sysctl', + * a command that bypasses the normal getopt, and that + * is available on those platforms that use this + * sysctl emulation. + * in this case, a negative oldlen signals that *oldp + * is actually a FILE* to print somewhere else than stdout + */ + + int l; + int ret; + struct dn_id* oid; + struct sysctlhead* entry; + char* pstring; + char* pdata; + FILE* fp; + + if((oldlenp != NULL) && (*oldlenp < 0)) + fp = (FILE*)oldp; + else + fp = stdout; + if(newp != NULL && newlen != 0) + { + //this is a set + l = sizeof(struct dn_id) + sizeof(struct sysctlhead) + strlen(name)+1 + newlen; + oid = malloc(l); + if (oid == NULL) + return -1; + oid->len = l; + oid->type = DN_SYSCTL_SET; + oid->id = DN_API_VERSION; + + entry = (struct sysctlhead*)(oid+1); + pdata = (unsigned char*)(entry+1); + pstring = pdata + newlen; + + entry->blocklen = ((sizeof(struct sysctlhead) + strlen(name)+1 + newlen) + 3) & ~3; + entry->namelen = strlen(name)+1; + entry->flags = 0; + entry->datalen = newlen; + + bcopy(newp, pdata, newlen); + bcopy(name, pstring, strlen(name)+1); + + ret = do_cmd(IP_DUMMYNET3, oid, (uintptr_t)l); + if (ret != 0) + return -1; + } + else + { + //this is a get or a print + l = sizeof(struct dn_id); + oid = malloc(l); + if (oid == NULL) + return -1; + oid->len = l; + oid->type = DN_SYSCTL_GET; + oid->id = DN_API_VERSION; + + ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l); + if (ret != 0) + return -1; + + l=oid->id; + free(oid); + oid = malloc(l); + if (oid == NULL) + return -1; + oid->len = l; + oid->type = DN_SYSCTL_GET; + oid->id = DN_API_VERSION; + + ret = do_cmd(-IP_DUMMYNET3, oid, (uintptr_t)&l); + if (ret != 0) + return -1; + + entry = (struct sysctlhead*)(oid+1); + while(entry->blocklen != 0) + { + pdata = (unsigned char*)(entry+1); + pstring = pdata+entry->datalen; + + //time to check if this is a get or a print + if(name != NULL && oldp != NULL && *oldlenp > 0) + { + //this is a get + if(strcmp(name,pstring) == 0) + { + //match found, sanity chech on len + if(*oldlenp < entry->datalen) + { + printf("%s error: buffer too small\n",__FUNCTION__); + return -1; + } + *oldlenp = entry->datalen; + bcopy(pdata, oldp, *oldlenp); + return 0; + } + } + else + { + //this is a print + if( name == NULL ) + goto print; + if ( (strncmp(pstring,name,strlen(name)) == 0) && ( pstring[strlen(name)]=='\0' || pstring[strlen(name)]=='.' ) ) + goto print; + else + goto skip; +print: + fprintf(fp, "%s: ",pstring); + switch( entry->flags >> 2 ) + { + case SYSCTLTYPE_LONG: + fprintf(fp, "%li ", *(long*)(pdata)); + break; + case SYSCTLTYPE_UINT: + fprintf(fp, "%u ", *(unsigned int*)(pdata)); + break; + case SYSCTLTYPE_ULONG: + fprintf(fp, "%lu ", *(unsigned long*)(pdata)); + break; + case SYSCTLTYPE_INT: + default: + fprintf(fp, "%i ", *(int*)(pdata)); + } + if( (entry->flags & 0x00000003) == CTLFLAG_RD ) + fprintf(fp, "\t(read only)\n"); + else + fprintf(fp, "\n"); +skip: ; + } + entry = (struct sysctlhead*)((unsigned char*)entry + entry->blocklen); + } + free(oid); + return 0; + } + //fallback for invalid options + return -1; + +#else /* __linux__ */ FILE *fp; char *basename = "/sys/module/ipfw_mod/parameters/"; char filename[256]; /* full filename */ @@ -124,10 +313,6 @@ sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, int ret = 0; /* return value */ int d; - /* debug message */ - if (0) fprintf(stderr, "%s name %s oldp %p oldlenp %p %d newp %p newlen %d\n", __FUNCTION__, name, \ - oldp, oldlenp, oldlenp ? *oldlenp : -1 , newp, (int) newlen); - if (name == NULL) /* XXX set errno */ return -1; @@ -175,5 +360,482 @@ sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, } return ret; +#endif /* __linux__ */ +} + +#ifdef _WIN32 +/* + * On windows, set/getsockopt are mapped to DeviceIoControl() + */ +int +wnd_setsockopt(int s, int level, int sopt_name, const void *optval, + socklen_t optlen) +{ + size_t len = sizeof (struct sockopt) + optlen; + struct sockopt *sock; + DWORD n; + BOOL result; + HANDLE _dev_h = (HANDLE)s; + + /* allocate a data structure for communication */ + sock = malloc(len); + if (sock == NULL) + return -1; + + sock->sopt_dir = SOPT_SET; + sock->sopt_name = sopt_name; + sock->sopt_valsize = optlen; + sock->sopt_val = (void *)(sock+1); + + memcpy(sock->sopt_val, optval, optlen); + result = DeviceIoControl (_dev_h, IP_FW_SETSOCKOPT, sock, len, + NULL, 0, &n, NULL); + free (sock); + + return (result ? 0 : -1); +} + +int +wnd_getsockopt(int s, int level, int sopt_name, void *optval, + socklen_t *optlen) +{ + size_t len = sizeof (struct sockopt) + *optlen; + struct sockopt *sock; + DWORD n; + BOOL result; + HANDLE _dev_h = (HANDLE)s; + + sock = malloc(len); + if (sock == NULL) + return -1; + + sock->sopt_dir = SOPT_GET; + sock->sopt_name = sopt_name; + sock->sopt_valsize = *optlen; + sock->sopt_val = (void *)(sock+1); + + memcpy (sock->sopt_val, optval, *optlen); + + result = DeviceIoControl (_dev_h, IP_FW_GETSOCKOPT, sock, len, + sock, len, &n, NULL); + //printf("len = %i, returned = %u, valsize = %i\n",len,n,sock->sopt_valsize); + *optlen = sock->sopt_valsize; + memcpy (optval, sock->sopt_val, *optlen); + free (sock); + return (result ? 0 : -1); +} + +int +my_socket(int domain, int ty, int proto) +{ + TCHAR *pcCommPort = TEXT("\\\\.\\Ipfw"); + HANDLE _dev_h = INVALID_HANDLE_VALUE; + + /* Special Handling For Accessing Device On Windows 2000 Terminal Server + See Microsoft KB Article 259131 */ + if (_dev_h == INVALID_HANDLE_VALUE) { + _dev_h = CreateFile (pcCommPort, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + if (_dev_h == INVALID_HANDLE_VALUE) { + printf("%s failed %u, cannot talk to kernel module\n", + __FUNCTION__, (unsigned)GetLastError()); + return -1; + } + return (int)_dev_h; +} + +struct hostent* gethostbyname2(const char *name, int af) +{ + return gethostbyname(name); +} + +struct ether_addr* ether_aton(const char *a) +{ + fprintf(stderr, "%s empty\n", __FUNCTION__); + return NULL; +} + +#ifdef TCC +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +#define PROGNAME "ipfw" +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(nargc, nargv, ostr) + int nargc; + char * const nargv[]; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || *place == 0) { /* update scanning pointer */ + optreset = 0; + place = nargv[optind]; + if (optind >= nargc || *place++ != '-') { + /* Argument is absent or is not an option */ + place = EMSG; + return (-1); + } + optopt = *place++; + if (optopt == '-' && *place == 0) { + /* "--" => end of options */ + ++optind; + place = EMSG; + return (-1); + } + if (optopt == 0) { + /* Solitary '-', treat as a '-' option + if the program (eg su) is looking for it. */ + place = EMSG; + if (strchr(ostr, '-') == NULL) + return (-1); + optopt = '-'; + } + } else + optopt = *place++; + + /* See if option letter is one the caller wanted... */ + if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) { + if (*place == 0) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", PROGNAME, + optopt); + return (BADCH); + } + + /* Does this option need an argument? */ + if (oli[1] != ':') { + /* don't need argument */ + optarg = NULL; + if (*place == 0) + ++optind; + } else { + /* Option-argument is either the rest of this argument or the + entire next argument. */ + if (*place) + optarg = place; + else if (nargc > ++optind) + optarg = nargv[optind]; + else { + /* option-argument absent */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + PROGNAME, optopt); + return (BADCH); + } + place = EMSG; + ++optind; + } + return (optopt); /* return option letter */ +} + +//static FILE *err_file = stderr; +void +verrx(int ex, int eval, const char *fmt, va_list ap) +{ + fprintf(stderr, "%s: ", PROGNAME); + if (fmt != NULL) + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + if (ex) + exit(eval); +} +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(1, eval, fmt, ap); + va_end(ap); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(0, 0, fmt, ap); + va_end(ap); } -#endif /* __linux__ || _WIN32 */ + +char * +strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +static unsigned char +tolower(unsigned char c) +{ + return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c; +} + +static int isdigit(unsigned char c) +{ + return (c >= '0' && c <= '9'); +} + +static int isxdigit(unsigned char c) +{ + return (index("0123456789ABCDEFabcdef", c) ? 1 : 0); +} + +static int isspace(unsigned char c) +{ + return (index(" \t\n\r", c) ? 1 : 0); +} + +static int isascii(unsigned char c) +{ + return (c < 128); +} + +static int islower(unsigned char c) +{ + return (c >= 'a' && c <= 'z'); +} + +int +strcasecmp(const char *s1, const char *s2) +{ + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); +} + +intmax_t +strtoimax(const char * restrict nptr, char ** restrict endptr, int base) +{ + return strtol(nptr, endptr,base); +} + +void +setservent(int a) +{ +} + +#define NS_INADDRSZ 128 + +int +inet_pton(int af, const char *src, void *dst) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[NS_INADDRSZ], *tp; + + if (af != AF_INET) { + errno = EINVAL; + return -1; + } + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return (0); + if (new > 255) + return (0); + *tp = new; + if (!saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +const char * +inet_ntop(int af, const void *_src, char *dst, socklen_t size) +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + const u_char *src = _src; + int l; + if (af != AF_INET) { + errno = EINVAL; + return NULL; + } + + l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || (socklen_t) l >= size) { + errno = ENOSPC; + return (NULL); + } + strlcpy(dst, tmp, size); + return (dst); +} + +/*% + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(const char *cp, struct in_addr *addr) { + u_long val; + int base, n; + char c; + u_int8_t parts[4]; + u_int8_t *pp = parts; + int digit; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit((unsigned char)c)) + return (0); + val = 0; base = 10; digit = 0; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else { + base = 8; + digit = 1 ; + } + } + for (;;) { + if (isascii(c) && isdigit((unsigned char)c)) { + if (base == 8 && (c == '8' || c == '9')) + return (0); + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if (base == 16 && isascii(c) && + isxdigit((unsigned char)c)) { + val = (val << 4) | + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xffU) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c))) + return (0); + /* + * Did we get a valid digit? + */ + if (!digit) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + case 1: /*%< a -- 32 bits */ + break; + + case 2: /*%< a.b -- 8.24 bits */ + if (val > 0xffffffU) + return (0); + val |= parts[0] << 24; + break; + + case 3: /*%< a.b.c -- 8.8.16 bits */ + if (val > 0xffffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /*%< a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr != NULL) + addr->s_addr = htonl(val); + return (1); +} + +#endif /* TCC */ + +#endif /* _WIN32 */