/* * Copyright (c) 2014, Peter Haag * Copyright (c) 2009, Peter Haag * Copyright (c) 2008-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the author nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * * * $Author: haag $ * * $Id: ipconv.c 39 2009-11-25 08:11:15Z haag $ * * $LastChangedRevision: 39 $ * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_RESOLV_H #include #endif #ifdef HAVE_STDINT_H #include #endif #include "nffile.h" #include "util.h" #include "ipconv.h" static int parse_ipv4(const char *src, uint32_t *dst, int *bytes); static int parse_ipv6(const char *src, uint64_t *dst, int *bytes); static int lookup_host(const char *hostname, uint64_t *iplist, uint32_t *num_ip ); int parse_ip(int *af, const char *src, uint64_t *dst, int *bytes, int lookup, uint32_t *num_ip ) { char *alpha = "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY"; uint32_t v4addr; int ret; // check for IPv6 address if ( strchr(src, ':') != NULL ) { *af = PF_INET6; // check for alpha chars -> hostname -> lookup } else if ( strpbrk(src, alpha)) { *af = 0; if ( lookup == STRICT_IP ) return -1; else return lookup_host(src, dst, num_ip ); // it's IPv4 } else *af = PF_INET; *num_ip = 1; switch (*af) { case AF_INET: ret = (parse_ipv4(src, &v4addr, bytes)); dst[0] = 0; dst[1] = ntohl(v4addr) & 0xffffffffLL ; return ret; break; case AF_INET6: ret = (parse_ipv6(src, dst, bytes)); dst[0] = ntohll(dst[0]); dst[1] = ntohll(dst[1]); return ret; break; } /* NOTREACHED */ return 0; } static int parse_ipv4(const char *src, uint32_t *dst, int *bytes) { static const char digits[] = "0123456789"; int saw_digit, ch; uint8_t tmp[4], *tp; saw_digit = 0; *bytes = 0; *(tp = tmp) = 0; memset(tmp, 0, sizeof(tmp)); while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { unsigned int new = *tp * 10 + (pch - digits); if (new > 255) return (0); if (! saw_digit) { if (++(*bytes) > 4) return (0); saw_digit = 1; } *tp = new; } else if (ch == '.' && saw_digit) { if (*bytes == 4) return (0); *++tp = 0; saw_digit = 0; if ( !(*src) ) return 0; } else return (0); } memcpy(dst, tmp, sizeof(tmp)); return (1); } static int parse_ipv6(const char *src, uint64_t *dst, int *bytes) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; uint8_t tmp[16], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; u_int val; memset((tp = tmp), '\0', sizeof(tmp)); endp = tp + sizeof(tmp); colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } else if (*src == '\0') { return (0); } if (tp + sizeof(uint16_t) > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + 4) <= endp) && parse_ipv4(curtok, (uint32_t *)tp, bytes) > 0) { tp += 4; saw_xdigit = 0; break; /* '\0' was seen by parse_ipv4(). */ } return (0); } if (saw_xdigit) { if (tp + sizeof(uint16_t) > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } *bytes = 16 - ( endp - tp ); memcpy(dst, tmp, sizeof(tmp)); return (1); } static int lookup_host(const char *hostname, uint64_t *iplist, uint32_t *num_ip ) { struct addrinfo hints, *res, *r; int errcode, i, len; char addrstr[128]; char reverse[256]; void *ptr; printf("Resolving %s ...\n", hostname); memset (&hints, 0, sizeof (hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags |= AI_CANONNAME; errcode = getaddrinfo (hostname, NULL, &hints, &res); if (errcode != 0) { fprintf(stderr, "Failed to resolve IP address for %s: %s\n", hostname, gai_strerror(errno)); return 0; } // count the number of records found *num_ip = 0; // remember res for later free() r = res; i = 0; while (res) { if ( *num_ip >= MAXHOSTS ) { printf ("Too man IP addresses in DNS response\n"); return 1; } switch (res->ai_family) { case PF_INET: ptr = &(((struct sockaddr_in *) res->ai_addr)->sin_addr); iplist[i++] = 0; iplist[i++] = ntohl(*(uint32_t *)ptr) & 0xffffffffLL ; len = sizeof(struct sockaddr_in); break; case AF_INET6: ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; iplist[i++] = ntohll(((uint64_t *)ptr)[0]); iplist[i++] = ntohll(((uint64_t *)ptr)[1]); len = sizeof(struct sockaddr_in6); break; default: { // not handled res = res->ai_next; continue; } } inet_ntop (res->ai_family, ptr, addrstr, 100); addrstr[99] = '\0'; if ( (errcode = getnameinfo(res->ai_addr, len, reverse, sizeof(reverse), NULL,0,0)) != 0 ) { snprintf(reverse, sizeof(reverse)-1, ""); // fprintf(stderr, "Failed to reverse lookup %s: %s\n", addrstr, gai_strerror(errcode)); } printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr, reverse ); res = res->ai_next; (*num_ip)++; } freeaddrinfo(r); return 1; } // End of lookup_host int set_nameserver(char *ns) { struct hostent *host; res_init(); host = gethostbyname(ns); if (host == NULL) { (void) fprintf(stderr,"Can not resolv nameserver %s: %s\n", ns, hstrerror(h_errno)); return 0; } (void) memcpy((void *)&_res.nsaddr_list[0].sin_addr, (void *)host->h_addr_list[0], (size_t)host->h_length); _res.nscount = 1; return 1; } // End of set_nameserver /* int main( int argc, char **argv ) { char *s, t[64]; uint64_t anyaddr[2]; uint32_t num_ip; int af, ret, bytes; s = argv[1]; if (argc == 3 && !set_nameserver(argv[2]) ) return 0; lookup_host(s, &num_ip); return 0; ret = parse_ip(&af, s, anyaddr, &bytes); if ( ret != 1 ) { printf("Parse failed!\n"); return 0; } if ( af == PF_INET ) inet_ntop(af, &(((uint32_t *)anyaddr)[3]), t, 64); else inet_ntop(af, anyaddr, t, 64); printf("Convert back: %s => %s %i bytes\n", s, t, bytes); } */