2 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * Copyright (c) 2006, Thomas Bernard
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
42 #include <sys/sockio.h>
51 # define AF_LINK AF_INET
54 # include <net/if_dl.h>
61 # include <linux/rtnetlink.h>
62 # include <linux/netlink.h>
64 #include "upnpglobalvars.h"
65 #include "getifaddr.h"
71 getifaddr(const char *ifname
)
74 struct ifaddrs
*ifap
, *p
;
75 struct sockaddr_in
*addr_in
;
77 if (getifaddrs(&ifap
) != 0)
79 DPRINTF(E_ERROR
, L_GENERAL
, "getifaddrs(): %s\n", strerror(errno
));
83 for (p
= ifap
; p
!= NULL
; p
= p
->ifa_next
)
85 if (!p
->ifa_addr
|| p
->ifa_addr
->sa_family
!= AF_INET
)
87 if (ifname
&& strcmp(p
->ifa_name
, ifname
) != 0)
89 addr_in
= (struct sockaddr_in
*)p
->ifa_addr
;
90 if (!ifname
&& (p
->ifa_flags
& (IFF_LOOPBACK
| IFF_SLAVE
)))
92 memcpy(&lan_addr
[n_lan_addr
].addr
, &addr_in
->sin_addr
, sizeof(lan_addr
[n_lan_addr
].addr
));
93 if (!inet_ntop(AF_INET
, &addr_in
->sin_addr
, lan_addr
[n_lan_addr
].str
, sizeof(lan_addr
[0].str
)) )
95 DPRINTF(E_ERROR
, L_GENERAL
, "inet_ntop(): %s\n", strerror(errno
));
98 addr_in
= (struct sockaddr_in
*)p
->ifa_netmask
;
99 memcpy(&lan_addr
[n_lan_addr
].mask
, &addr_in
->sin_addr
, sizeof(lan_addr
[n_lan_addr
].mask
));
100 lan_addr
[n_lan_addr
].ifindex
= if_nametoindex(p
->ifa_name
);
101 lan_addr
[n_lan_addr
].snotify
= OpenAndConfSSDPNotifySocket(&lan_addr
[n_lan_addr
]);
102 if (lan_addr
[n_lan_addr
].snotify
>= 0)
104 if (ifname
|| n_lan_addr
>= MAX_LAN_ADDR
)
110 DPRINTF(E_ERROR
, L_GENERAL
, "Network interface %s not found\n", ifname
);
114 int s
= socket(PF_INET
, SOCK_STREAM
, 0);
115 struct sockaddr_in addr
;
121 memset(&ifc
, '\0', sizeof(ifc
));
123 ifc
.ifc_len
= sizeof(buf
);
125 if (ioctl(s
, SIOCGIFCONF
, &ifc
) < 0)
127 DPRINTF(E_ERROR
, L_GENERAL
, "SIOCGIFCONF: %s\n", strerror(errno
));
132 n
= ifc
.ifc_len
/ sizeof(struct ifreq
);
133 for (i
= 0; i
< n
; i
++)
135 ifr
= &ifc
.ifc_req
[i
];
136 if (ifname
&& strcmp(ifr
->ifr_name
, ifname
) != 0)
139 (ioctl(s
, SIOCGIFFLAGS
, ifr
) < 0 || ifr
->ifr_ifru
.ifru_flags
& IFF_LOOPBACK
))
141 if (ioctl(s
, SIOCGIFADDR
, ifr
) < 0)
143 memcpy(&addr
, &(ifr
->ifr_addr
), sizeof(addr
));
144 memcpy(&lan_addr
[n_lan_addr
].addr
, &addr
.sin_addr
, sizeof(lan_addr
[n_lan_addr
].addr
));
145 if (!inet_ntop(AF_INET
, &addr
.sin_addr
, lan_addr
[n_lan_addr
].str
, sizeof(lan_addr
[0].str
)))
147 DPRINTF(E_ERROR
, L_GENERAL
, "inet_ntop(): %s\n", strerror(errno
));
151 if (ioctl(s
, SIOCGIFNETMASK
, ifr
) < 0)
153 memcpy(&addr
, &(ifr
->ifr_addr
), sizeof(addr
));
154 memcpy(&lan_addr
[n_lan_addr
].mask
, &addr
.sin_addr
, sizeof(addr
));
155 lan_addr
[n_lan_addr
].ifindex
= if_nametoindex(ifr
->ifr_name
);
156 lan_addr
[n_lan_addr
].snotify
= OpenAndConfSSDPNotifySocket(&lan_addr
[n_lan_addr
]);
157 if (lan_addr
[n_lan_addr
].snotify
>= 0)
159 if (ifname
|| n_lan_addr
>= MAX_LAN_ADDR
)
163 if (ifname
&& i
== n
)
165 DPRINTF(E_ERROR
, L_GENERAL
, "Network interface %s not found\n", ifname
);
173 getsyshwaddr(char *buf
, int len
)
175 unsigned char mac
[6];
177 #if defined(HAVE_GETIFADDRS) && !defined (__linux__) && !defined (__sun__)
178 struct ifaddrs
*ifap
, *p
;
179 struct sockaddr_in
*addr_in
;
182 if (getifaddrs(&ifap
) != 0)
184 DPRINTF(E_ERROR
, L_GENERAL
, "getifaddrs(): %s\n", strerror(errno
));
187 for (p
= ifap
; p
!= NULL
; p
= p
->ifa_next
)
189 if (p
->ifa_addr
&& p
->ifa_addr
->sa_family
== AF_LINK
)
191 addr_in
= (struct sockaddr_in
*)p
->ifa_addr
;
192 a
= (htonl(addr_in
->sin_addr
.s_addr
) >> 0x18) & 0xFF;
195 #if defined(__linux__)
198 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
201 strncpy(ifr
.ifr_name
, p
->ifa_name
, IFNAMSIZ
);
202 ret
= ioctl(fd
, SIOCGIFHWADDR
, &ifr
);
206 memcpy(mac
, ifr
.ifr_hwaddr
.sa_data
, 6);
208 if (p
->ifa_addr
->sa_family
!= AF_LINK
)
210 struct sockaddr_dl
*sdl
;
211 sdl
= (struct sockaddr_dl
*)p
->ifa_addr
;
212 if (sdl
->sdl_alen
!= 6)
214 memcpy(mac
, LLADDR(sdl
), 6);
216 if (MACADDR_IS_ZERO(mac
))
224 struct if_nameindex
*ifaces
, *if_idx
;
228 memset(&mac
, '\0', sizeof(mac
));
229 /* Get the spatially unique node identifier */
230 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
234 ifaces
= if_nameindex();
241 for (if_idx
= ifaces
; if_idx
->if_index
; if_idx
++)
243 strncpyt(ifr
.ifr_name
, if_idx
->if_name
, IFNAMSIZ
);
244 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) < 0)
246 if (ifr
.ifr_ifru
.ifru_flags
& IFF_LOOPBACK
)
248 if (ioctl(fd
, SIOCGIFHWADDR
, &ifr
) < 0)
251 if (MACADDR_IS_ZERO(ifr
.ifr_addr
.sa_data
))
253 memcpy(mac
, ifr
.ifr_addr
.sa_data
, 6);
255 if (MACADDR_IS_ZERO(ifr
.ifr_hwaddr
.sa_data
))
257 memcpy(mac
, ifr
.ifr_hwaddr
.sa_data
, 6);
262 if_freenameindex(ifaces
);
268 sprintf(buf
, "%02x%02x%02x%02x%02x%02x",
269 mac
[0]&0xFF, mac
[1]&0xFF, mac
[2]&0xFF,
270 mac
[3]&0xFF, mac
[4]&0xFF, mac
[5]&0xFF);
272 memmove(buf
, mac
, 6);
278 get_remote_mac(struct in_addr ip_addr
, unsigned char *mac
)
280 struct in_addr arp_ent
;
283 int matches
, hwtype
, flags
;
284 memset(mac
, 0xFF, 6);
286 arp
= fopen("/proc/net/arp", "r");
291 matches
= fscanf(arp
, "%15s 0x%8X 0x%8X %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
292 remote_ip
, &hwtype
, &flags
,
293 &mac
[0], &mac
[1], &mac
[2], &mac
[3], &mac
[4], &mac
[5]);
296 inet_pton(AF_INET
, remote_ip
, &arp_ent
);
297 if (ip_addr
.s_addr
== arp_ent
.s_addr
)
305 memset(mac
, 0xFF, 6);
313 reload_ifaces(int force_notify
)
315 struct in_addr old_addr
[MAX_LAN_ADDR
];
318 memset(&old_addr
, 0xFF, sizeof(old_addr
));
319 for (i
= 0; i
< n_lan_addr
; i
++)
321 memcpy(&old_addr
[i
], &lan_addr
[i
].addr
, sizeof(struct in_addr
));
322 close(lan_addr
[i
].snotify
);
328 getifaddr(runtime_vars
.ifaces
[i
]);
330 } while (i
< MAX_LAN_ADDR
&& runtime_vars
.ifaces
[i
]);
332 for (i
= 0; i
< n_lan_addr
; i
++)
334 for (j
= 0; j
< MAX_LAN_ADDR
; j
++)
336 if (memcmp(&lan_addr
[i
].addr
, &old_addr
[j
], sizeof(struct in_addr
)) == 0)
339 /* Send out startup notifies if it's a new interface, or on SIGHUP */
340 if (force_notify
|| j
== MAX_LAN_ADDR
)
342 DPRINTF(E_INFO
, L_GENERAL
, "Enabling interface %s/%s\n",
343 lan_addr
[i
].str
, inet_ntoa(lan_addr
[i
].mask
));
344 SendSSDPGoodbyes(lan_addr
[i
].snotify
);
345 SendSSDPNotifies(lan_addr
[i
].snotify
, lan_addr
[i
].str
,
346 runtime_vars
.port
, runtime_vars
.notify_interval
);
352 OpenAndConfMonitorSocket(void)
355 struct sockaddr_nl addr
;
359 s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
362 perror("couldn't open NETLINK_ROUTE socket");
366 memset(&addr
, 0, sizeof(addr
));
367 addr
.nl_family
= AF_NETLINK
;
368 addr
.nl_groups
= RTMGRP_IPV4_IFADDR
;
370 ret
= bind(s
, (struct sockaddr
*)&addr
, sizeof(addr
));
373 perror("couldn't bind");
385 ProcessMonitorEvent(struct event
*ev
)
391 struct nlmsghdr
*nlh
;
394 nlh
= (struct nlmsghdr
*)buf
;
396 len
= recv(s
, nlh
, sizeof(buf
), 0);
399 while ((NLMSG_OK(nlh
, len
)) && (nlh
->nlmsg_type
!= NLMSG_DONE
))
401 if (nlh
->nlmsg_type
== RTM_NEWADDR
||
402 nlh
->nlmsg_type
== RTM_DELADDR
)
406 nlh
= NLMSG_NEXT(nlh
, len
);