1/* $Id: upnputils.c,v 1.10 2014/11/07 11:53:39 nanard Exp $ */ 2/* MiniUPnP project 3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ 4 * (c) 2006-2014 Thomas Bernard 5 * This software is subject to the conditions detailed 6 * in the LICENCE file provided within the distribution */ 7 8#include "config.h" 9 10#include <stdio.h> 11#include <string.h> 12#include <syslog.h> 13#include <unistd.h> 14#include <fcntl.h> 15#include <sys/types.h> 16#include <sys/socket.h> 17#include <netinet/in.h> 18#include <arpa/inet.h> 19#ifdef AF_LINK 20#include <net/if_dl.h> 21#endif 22#include <errno.h> 23 24#include "upnputils.h" 25#include "upnpglobalvars.h" 26#ifdef ENABLE_IPV6 27#include "getroute.h" 28#endif 29 30int 31sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size) 32{ 33 char buffer[64]; 34 unsigned short port = 0; 35 int n = -1; 36 37 switch(addr->sa_family) 38 { 39#ifdef AF_INET6 40 case AF_INET6: 41 if(inet_ntop(addr->sa_family, 42 &((struct sockaddr_in6 *)addr)->sin6_addr, 43 buffer, sizeof(buffer)) == NULL) { 44 snprintf(buffer, sizeof(buffer), "inet_ntop: %s", strerror(errno)); 45 } 46 port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); 47 if(((struct sockaddr_in6 *)addr)->sin6_scope_id > 0) { 48 char ifname[IF_NAMESIZE]; 49 if(if_indextoname(((struct sockaddr_in6 *)addr)->sin6_scope_id, ifname) == NULL) 50 strncpy(ifname, "ERROR", sizeof(ifname)); 51 n = snprintf(str, size, "[%s%%%s]:%hu", buffer, ifname, port); 52 } else { 53 n = snprintf(str, size, "[%s]:%hu", buffer, port); 54 } 55 break; 56#endif /* AF_INET6 */ 57 case AF_INET: 58 if(inet_ntop(addr->sa_family, 59 &((struct sockaddr_in *)addr)->sin_addr, 60 buffer, sizeof(buffer)) == NULL) { 61 snprintf(buffer, sizeof(buffer), "inet_ntop: %s", strerror(errno)); 62 } 63 port = ntohs(((struct sockaddr_in *)addr)->sin_port); 64 n = snprintf(str, size, "%s:%hu", buffer, port); 65 break; 66#ifdef AF_LINK 67#if defined(__sun) 68 /* solaris does not seem to have link_ntoa */ 69 /* #define link_ntoa _link_ntoa */ 70#define link_ntoa(x) "dummy-link_ntoa" 71#endif 72 case AF_LINK: 73 { 74 struct sockaddr_dl * sdl = (struct sockaddr_dl *)addr; 75 n = snprintf(str, size, "index=%hu type=%d %s", 76 sdl->sdl_index, sdl->sdl_type, 77 link_ntoa(sdl)); 78 } 79 break; 80#endif /* AF_LINK */ 81 default: 82 n = snprintf(str, size, "unknown address family %d", addr->sa_family); 83#if 0 84 n = snprintf(str, size, "unknown address family %d " 85 "%02x %02x %02x %02x %02x %02x %02x %02x", 86 addr->sa_family, 87 addr->sa_data[0], addr->sa_data[1], (unsigned)addr->sa_data[2], addr->sa_data[3], 88 addr->sa_data[4], addr->sa_data[5], (unsigned)addr->sa_data[6], addr->sa_data[7]); 89#endif 90 } 91 return n; 92} 93 94 95int 96set_non_blocking(int fd) 97{ 98 int flags = fcntl(fd, F_GETFL); 99 if(flags < 0) 100 return 0; 101 if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) 102 return 0; 103 return 1; 104} 105 106struct lan_addr_s * 107get_lan_for_peer(const struct sockaddr * peer) 108{ 109 struct lan_addr_s * lan_addr = NULL; 110#ifdef DEBUG 111 char dbg_str[64]; 112#endif /* DEBUG */ 113 114#ifdef ENABLE_IPV6 115 if(peer->sa_family == AF_INET6) 116 { 117 struct sockaddr_in6 * peer6 = (struct sockaddr_in6 *)peer; 118 if(IN6_IS_ADDR_V4MAPPED(&peer6->sin6_addr)) 119 { 120 struct in_addr peer_addr; 121 memcpy(&peer_addr, &peer6->sin6_addr.s6_addr[12], 4); 122 for(lan_addr = lan_addrs.lh_first; 123 lan_addr != NULL; 124 lan_addr = lan_addr->list.le_next) 125 { 126 if( (peer_addr.s_addr & lan_addr->mask.s_addr) 127 == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) 128 break; 129 } 130 } 131 else 132 { 133 int index = -1; 134 if(peer6->sin6_scope_id > 0) 135 index = (int)peer6->sin6_scope_id; 136 else 137 { 138 if(get_src_for_route_to(peer, NULL, NULL, &index) < 0) 139 return NULL; 140 } 141 syslog(LOG_DEBUG, "%s looking for LAN interface index=%d", 142 "get_lan_for_peer()", index); 143 for(lan_addr = lan_addrs.lh_first; 144 lan_addr != NULL; 145 lan_addr = lan_addr->list.le_next) 146 { 147 syslog(LOG_DEBUG, 148 "ifname=%s index=%u str=%s addr=%08x mask=%08x", 149 lan_addr->ifname, lan_addr->index, 150 lan_addr->str, 151 ntohl(lan_addr->addr.s_addr), 152 ntohl(lan_addr->mask.s_addr)); 153 if(index == (int)lan_addr->index) 154 break; 155 } 156 } 157 } 158 else if(peer->sa_family == AF_INET) 159 { 160#endif /* ENABLE_IPV6 */ 161 for(lan_addr = lan_addrs.lh_first; 162 lan_addr != NULL; 163 lan_addr = lan_addr->list.le_next) 164 { 165 if( (((const struct sockaddr_in *)peer)->sin_addr.s_addr & lan_addr->mask.s_addr) 166 == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) 167 break; 168 } 169#ifdef ENABLE_IPV6 170 } 171#endif /* ENABLE_IPV6 */ 172 173#ifdef DEBUG 174 sockaddr_to_string(peer, dbg_str, sizeof(dbg_str)); 175 if(lan_addr) { 176 syslog(LOG_DEBUG, "%s: %s found in LAN %s %s", 177 "get_lan_for_peer()", dbg_str, 178 lan_addr->ifname, lan_addr->str); 179 } else { 180 syslog(LOG_DEBUG, "%s: %s not found !", "get_lan_for_peer()", 181 dbg_str); 182 } 183#endif /* DEBUG */ 184 return lan_addr; 185} 186 187