To make IPV6 work with Solaris, add_interfaces() had to be modified.
I decided to reimplement it with a getifaddrs() based implementation,
which is available from Solaris 11 upwards, and also on FreeBSD and
Linux. By default, the latter continues to use the netlink based
variant.
... | ... |
@@ -1785,7 +1785,7 @@ ifeq ($(CC_NAME), suncc) |
1785 | 1785 |
endif |
1786 | 1786 |
OLD_SOLARIS= $(shell echo "$(OSREL)" | \ |
1787 | 1787 |
sed -e 's/^5\.[0-6][^0-9]*$$/yes/' ) |
1788 |
- LIBS+= -L$(LOCALBASE)/lib -lxnet -lnsl |
|
1788 |
+ LIBS+= -L$(LOCALBASE)/lib -lxnet -lsocket -lnsl |
|
1789 | 1789 |
ifeq ($(OLD_SOLARIS), yes) |
1790 | 1790 |
LIBS+=-lposix4 |
1791 | 1791 |
else |
... | ... |
@@ -41,6 +41,7 @@ |
41 | 41 |
|
42 | 42 |
#include <sys/ioctl.h> |
43 | 43 |
#include <net/if.h> |
44 |
+#include <ifaddrs.h> |
|
44 | 45 |
#ifdef HAVE_SYS_SOCKIO_H |
45 | 46 |
#include <sys/sockio.h> |
46 | 47 |
#endif |
... | ... |
@@ -1129,7 +1130,8 @@ error: |
1129 | 1129 |
return -1; |
1130 | 1130 |
|
1131 | 1131 |
} |
1132 |
-/* add all family type addresses of interface if_to the socket_info array |
|
1132 |
+/* add all family type addresses of interface if_name to the socket_info array |
|
1133 |
+ * if family ==0, uses all families |
|
1133 | 1134 |
* if if_name==0, adds all addresses on all interfaces |
1134 | 1135 |
* uses RTNETLINK sockets to get addresses on the present interface on LINUX |
1135 | 1136 |
* return: -1 on error, 0 on success |
... | ... |
@@ -1160,7 +1162,7 @@ int add_interfaces_via_netlink(char* if_name, int family, unsigned short port, |
1160 | 1160 |
LM_DBG("in add_iface_via_netlink Name %s Address %s\n", |
1161 | 1161 |
ifaces[i].name, tmp->addr); |
1162 | 1162 |
/* match family */ |
1163 |
- if (family == tmp->family){ |
|
1163 |
+ if (family && family == tmp->family){ |
|
1164 | 1164 |
/* check if loopback */ |
1165 | 1165 |
if (ifaces[i].flags & IFF_LOOPBACK){ |
1166 | 1166 |
LM_DBG("INTERFACE %s is loopback", ifaces[i].name); |
... | ... |
@@ -1182,129 +1184,49 @@ error: |
1182 | 1182 |
#endif /* __OS_linux */ |
1183 | 1183 |
|
1184 | 1184 |
/* add all family type addresses of interface if_name to the socket_info array |
1185 |
+ * if family ==0, uses all families |
|
1185 | 1186 |
* if if_name==0, adds all addresses on all interfaces |
1186 |
- * WARNING: it only works with ipv6 addresses on FreeBSD |
|
1187 | 1187 |
* return: -1 on error, 0 on success |
1188 | 1188 |
*/ |
1189 | 1189 |
int add_interfaces(char* if_name, int family, unsigned short port, |
1190 | 1190 |
unsigned short proto, |
1191 | 1191 |
struct addr_info** ai_l) |
1192 | 1192 |
{ |
1193 |
- struct ifconf ifc; |
|
1194 |
- struct ifreq ifr; |
|
1195 |
- struct ifreq ifrcopy; |
|
1196 |
- char* last; |
|
1197 |
- char* p; |
|
1198 |
- int size; |
|
1199 |
- int lastlen; |
|
1200 |
- int s; |
|
1201 | 1193 |
char* tmp; |
1202 | 1194 |
struct ip_addr addr; |
1203 |
- int ret; |
|
1195 |
+ int ret = -1; |
|
1204 | 1196 |
enum si_flags flags; |
1197 |
+ struct ifaddrs *ifap, *ifa; |
|
1205 | 1198 |
|
1206 |
-#ifdef HAVE_SOCKADDR_SA_LEN |
|
1207 |
- #ifndef MAX |
|
1208 |
- #define MAX(a,b) ( ((a)>(b))?(a):(b)) |
|
1209 |
- #endif |
|
1210 |
-#endif |
|
1211 |
- /* ipv4 or ipv6 only*/ |
|
1212 |
- flags=SI_NONE; |
|
1213 |
- s=socket(family, SOCK_DGRAM, 0); |
|
1214 |
- ret=-1; |
|
1215 |
- lastlen=0; |
|
1216 |
- ifc.ifc_req=0; |
|
1217 |
- for (size=100; ; size*=2){ |
|
1218 |
- ifc.ifc_len=size*sizeof(struct ifreq); |
|
1219 |
- ifc.ifc_req=(struct ifreq*) pkg_malloc(size*sizeof(struct ifreq)); |
|
1220 |
- if (ifc.ifc_req==0){ |
|
1221 |
- LM_ERR("memory allocation failure\n"); |
|
1222 |
- goto error; |
|
1223 |
- } |
|
1224 |
- if (ioctl(s, SIOCGIFCONF, &ifc)==-1){ |
|
1225 |
- if(errno==EBADF) return 0; /* invalid descriptor => no such ifs*/ |
|
1226 |
- LM_ERR("ioctl failed: %s\n", strerror(errno)); |
|
1227 |
- goto error; |
|
1228 |
- } |
|
1229 |
- if ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success, |
|
1230 |
- len not changed*/ |
|
1231 |
- lastlen=ifc.ifc_len; |
|
1232 |
- /* try a bigger array*/ |
|
1233 |
- pkg_free(ifc.ifc_req); |
|
1234 |
- } |
|
1235 |
- |
|
1236 |
- last=(char*)ifc.ifc_req+ifc.ifc_len; |
|
1237 |
- for(p=(char*)ifc.ifc_req; p<last; |
|
1238 |
- p+= |
|
1239 |
- #ifdef __OS_linux |
|
1240 |
- sizeof(ifr) /* works on x86_64 too */ |
|
1241 |
- #else |
|
1242 |
- (sizeof(ifr.ifr_name)+ |
|
1243 |
- #ifdef HAVE_SOCKADDR_SA_LEN |
|
1244 |
- MAX(ifr.ifr_addr.sa_len, sizeof(struct sockaddr)) |
|
1245 |
- #else |
|
1246 |
- ( (ifr.ifr_addr.sa_family==AF_INET)? |
|
1247 |
- sizeof(struct sockaddr_in): |
|
1248 |
- ((ifr.ifr_addr.sa_family==AF_INET6)? |
|
1249 |
- sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) ) |
|
1250 |
- #endif |
|
1251 |
- ) |
|
1252 |
- #endif |
|
1253 |
- ) |
|
1199 |
+ if (getifaddrs (&ifap) != 0) { |
|
1200 |
+ LM_ERR("getifaddrs failed\n"); |
|
1201 |
+ return -1; |
|
1202 |
+ } |
|
1203 |
+ |
|
1204 |
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) |
|
1254 | 1205 |
{ |
1255 |
- /* copy contents into ifr structure |
|
1256 |
- * warning: it might be longer (e.g. ipv6 address) */ |
|
1257 |
- memcpy(&ifr, p, sizeof(ifr)); |
|
1258 |
- if (ifr.ifr_addr.sa_family!=family){ |
|
1259 |
- /*printf("strange family %d skipping...\n", |
|
1260 |
- ifr->ifr_addr.sa_family);*/ |
|
1206 |
+ if (if_name && strcmp(if_name, ifa->ifa_name)) |
|
1261 | 1207 |
continue; |
1208 |
+ if (family && family != ifa->ifa_addr->sa_family) |
|
1209 |
+ continue; |
|
1210 |
+ sockaddr2ip_addr(&addr, (struct sockaddr*)ifa->ifa_addr); |
|
1211 |
+ tmp=ip_addr2a(&addr); |
|
1212 |
+ if (ifa->ifa_flags & IFF_LOOPBACK) |
|
1213 |
+ flags = SI_IS_LO; |
|
1214 |
+ else |
|
1215 |
+ flags = SI_NONE; |
|
1216 |
+ if (new_addr_info2list(tmp, flags, ai_l)!=0) |
|
1217 |
+ { |
|
1218 |
+ LM_ERR("new_addr_info2list failed\n"); |
|
1219 |
+ ret = -1; |
|
1220 |
+ break; |
|
1262 | 1221 |
} |
1263 |
- |
|
1264 |
- /*get flags*/ |
|
1265 |
- ifrcopy=ifr; |
|
1266 |
- if (ioctl(s, SIOCGIFFLAGS, &ifrcopy)!=-1){ /* ignore errors */ |
|
1267 |
- /* ignore down ifs only if listening on all of them*/ |
|
1268 |
- if (if_name==0){ |
|
1269 |
- /* if if not up, skip it*/ |
|
1270 |
- if (!(ifrcopy.ifr_flags & IFF_UP)) continue; |
|
1271 |
- } |
|
1272 |
- } |
|
1273 |
- |
|
1274 |
- |
|
1275 |
- |
|
1276 |
- if ((if_name==0)|| |
|
1277 |
- (strncmp(if_name, ifr.ifr_name, sizeof(ifr.ifr_name))==0)){ |
|
1278 |
- |
|
1279 |
- /*add address*/ |
|
1280 |
- sockaddr2ip_addr(&addr, |
|
1281 |
- (struct sockaddr*)(p+(long)&((struct ifreq*)0)->ifr_addr)); |
|
1282 |
- if ((tmp=ip_addr2a(&addr))==0) goto error; |
|
1283 |
- /* check if loopback */ |
|
1284 |
- if (ifrcopy.ifr_flags & IFF_LOOPBACK) |
|
1285 |
- flags|=SI_IS_LO; |
|
1286 |
- /* save the info */ |
|
1287 |
- if (new_addr_info2list(tmp, flags, ai_l)!=0){ |
|
1288 |
- LM_ERR("new_addr_info2list failed\n"); |
|
1289 |
- goto error; |
|
1290 |
- } |
|
1291 |
- ret=0; |
|
1292 |
- } |
|
1293 |
- /* |
|
1294 |
- printf("%s:\n", ifr->ifr_name); |
|
1295 |
- printf(" "); |
|
1296 |
- print_sockaddr(&(ifr->ifr_addr)); |
|
1297 |
- printf(" "); |
|
1298 |
- ls_ifflags(ifr->ifr_name, family, options); |
|
1299 |
- printf("\n");*/ |
|
1222 |
+ LM_DBG("If: %8s Fam: %8x Flg: %16lx Adr: %s\n", ifa->ifa_name, ifa->ifa_addr->sa_family, ifa->ifa_flags, tmp); |
|
1223 |
+ |
|
1224 |
+ ret = 0; |
|
1300 | 1225 |
} |
1301 |
- pkg_free(ifc.ifc_req); /*clean up*/ |
|
1302 |
- close(s); |
|
1226 |
+ freeifaddrs(ifap); |
|
1303 | 1227 |
return ret; |
1304 |
-error: |
|
1305 |
- if (ifc.ifc_req) pkg_free(ifc.ifc_req); |
|
1306 |
- close(s); |
|
1307 |
- return -1; |
|
1308 | 1228 |
} |
1309 | 1229 |
|
1310 | 1230 |
|
... | ... |
@@ -1474,7 +1396,7 @@ static int fix_socket_list(struct socket_info **list, int* type_flags) |
1474 | 1474 |
for (si=*list;si;){ |
1475 | 1475 |
next=si->next; |
1476 | 1476 |
ai_lst=0; |
1477 |
- if (add_interfaces(si->name.s, AF_INET, si->port_no, |
|
1477 |
+ if (add_interfaces(si->name.s, 0, si->port_no, |
|
1478 | 1478 |
si->proto, &ai_lst)!=-1){ |
1479 | 1479 |
if (si->flags & SI_IS_MHOMED){ |
1480 | 1480 |
if((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no, |