1 /*- 2 * Copyright (c) 2009 Internet Initiative Japan Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 /* $Id: net_utils.c,v 1.2 2010/07/01 03:38:17 yasuoka Exp $ */ 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #include <net/if.h> 31 #include <ifaddrs.h> 32 #include <netdb.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "net_utils.h" 37 38 #ifdef NPPPD_USE_RTEV 39 #include "rtev.h" 40 #endif 41 42 /** Get an interface name from sockaddr */ 43 const char * 44 get_ifname_by_sockaddr(struct sockaddr *sa, char *ifname) 45 { 46 struct ifaddrs *addr, *addr0; 47 struct in_addr *in4a, *in4b; 48 const char *ifname0 = NULL; 49 #ifdef INET6 50 struct in6_addr *in6a, *in6b; 51 #endif 52 53 ifname0 = NULL; 54 /* I want other way than linear search */ 55 getifaddrs(&addr0); 56 for (addr = addr0; ifname0 == NULL&& addr != NULL; 57 addr = addr->ifa_next) { 58 if (addr->ifa_addr->sa_family != sa->sa_family || 59 addr->ifa_addr->sa_len != sa->sa_len) 60 continue; 61 switch (addr->ifa_addr->sa_family) { 62 default: 63 continue; 64 case AF_INET: 65 in4a = &((struct sockaddr_in *)addr->ifa_addr) 66 ->sin_addr; 67 in4b = &((struct sockaddr_in *)sa)->sin_addr; 68 if (in4a->s_addr == in4b->s_addr) { 69 strlcpy(ifname, addr->ifa_name, IF_NAMESIZE); 70 ifname0 = ifname; 71 } 72 break; 73 #ifdef INET6 74 case AF_INET6: 75 in6a = &((struct sockaddr_in6 *)addr->ifa_addr) 76 ->sin6_addr; 77 in6b = &((struct sockaddr_in6 *)sa)->sin6_addr; 78 if (IN6_ARE_ADDR_EQUAL(in6a, in6b)) { 79 strlcpy(ifname, addr->ifa_name, IF_NAMESIZE); 80 ifname0 = ifname; 81 } 82 break; 83 #endif 84 } 85 } 86 freeifaddrs(addr0); 87 88 return ifname0; 89 } 90 /** 91 * Cconvert argument like "192.168.160.1:1723/tcp" or "[::1]:1723/tcp" to 92 * match getaddrinfo(3)'s specification and pass them to getaddrinfo(3). 93 */ 94 int 95 addrport_parse(const char *addrport, int proto, struct addrinfo **p_ai) 96 { 97 char buf[256]; 98 char *servp, *nodep, *slash; 99 struct addrinfo hints; 100 101 strlcpy(buf, addrport, sizeof(buf)); 102 if (buf[0] == '[' && (servp = strchr(buf, ']')) != NULL) { 103 nodep = buf + 1; 104 *servp++ = '\0'; 105 if (*servp != ':') 106 servp = NULL; 107 } else { 108 nodep = buf; 109 servp = strrchr(nodep, ':'); 110 } 111 if (servp != NULL) { 112 *servp = '\0'; 113 servp++; 114 slash = strrchr(servp, '/'); 115 if (slash != NULL) { 116 /* 117 * Ignore like "/tcp" 118 */ 119 *slash = '\0'; 120 slash++; 121 } 122 } else 123 servp = NULL; 124 memset(&hints, 0, sizeof(hints)); 125 hints.ai_flags = AI_NUMERICHOST; 126 hints.ai_family = AF_UNSPEC; 127 switch (proto) { 128 case IPPROTO_TCP: 129 hints.ai_socktype = SOCK_STREAM; 130 break; 131 case IPPROTO_UDP: 132 hints.ai_socktype = SOCK_DGRAM; 133 break; 134 } 135 hints.ai_protocol = proto; 136 137 return getaddrinfo(nodep, servp, &hints, p_ai); 138 } 139 140 /** 141 * Make a string like "192.168.160.1:1723" or "[::1]:1723" from a struct 142 * sockaddr 143 * 144 * @param buf the buffer to be stored a string 145 * @param lbuf the length of the buf 146 */ 147 const char * 148 addrport_tostring(struct sockaddr *sa, socklen_t salen, char *buf, int lbuf) 149 { 150 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 151 152 if (getnameinfo(sa, salen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), 153 NI_NUMERICHOST | NI_NUMERICSERV) != 0) 154 return NULL; 155 156 switch (sa->sa_family) { 157 case AF_INET6: 158 strlcpy(buf, "[", lbuf); 159 strlcat(buf, hbuf, lbuf); 160 strlcat(buf, "]:", lbuf); 161 strlcat(buf, sbuf, lbuf); 162 break; 163 case AF_INET: 164 strlcpy(buf, hbuf, lbuf); 165 strlcat(buf, ":", lbuf); 166 strlcat(buf, sbuf, lbuf); 167 break; 168 default: 169 return NULL; 170 } 171 172 return buf; 173 } 174 175 /** Convert 32bit IPv4 netmask to the prefix length in host byte order */ 176 int 177 netmask2prefixlen(uint32_t mask) 178 { 179 switch(mask) { 180 case 0x00000000: return 0; 181 case 0x80000000: return 1; 182 case 0xC0000000: return 2; 183 case 0xE0000000: return 3; 184 case 0xF0000000: return 4; 185 case 0xF8000000: return 5; 186 case 0xFC000000: return 6; 187 case 0xFE000000: return 7; 188 case 0xFF000000: return 8; 189 case 0xFF800000: return 9; 190 case 0xFFC00000: return 10; 191 case 0xFFE00000: return 11; 192 case 0xFFF00000: return 12; 193 case 0xFFF80000: return 13; 194 case 0xFFFC0000: return 14; 195 case 0xFFFE0000: return 15; 196 case 0xFFFF0000: return 16; 197 case 0xFFFF8000: return 17; 198 case 0xFFFFC000: return 18; 199 case 0xFFFFE000: return 19; 200 case 0xFFFFF000: return 20; 201 case 0xFFFFF800: return 21; 202 case 0xFFFFFC00: return 22; 203 case 0xFFFFFE00: return 23; 204 case 0xFFFFFF00: return 24; 205 case 0xFFFFFF80: return 25; 206 case 0xFFFFFFC0: return 26; 207 case 0xFFFFFFE0: return 27; 208 case 0xFFFFFFF0: return 28; 209 case 0xFFFFFFF8: return 29; 210 case 0xFFFFFFFC: return 30; 211 case 0xFFFFFFFE: return 31; 212 case 0xFFFFFFFF: return 32; 213 } 214 return -1; 215 } 216