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>
50 # define AF_LINK AF_INET
53 # include <net/if_dl.h>
60 # include <linux/rtnetlink.h>
61 # include <linux/netlink.h>
63 #include "upnpglobalvars.h"
64 #include "getifaddr.h"
72 getifaddr(const char *ifname
)
75 struct ifaddrs
*ifap
, *p
;
76 struct sockaddr_in
*addr_in
;
78 if (getifaddrs(&ifap
) != 0)
80 DPRINTF(E_ERROR
, L_GENERAL
, "getifaddrs(): %s\n", strerror(errno
));
84 for (p
= ifap
; p
!= NULL
; p
= p
->ifa_next
)
86 if (!p
->ifa_addr
|| p
->ifa_addr
->sa_family
!= AF_INET
)
88 if (ifname
&& strcmp(p
->ifa_name
, ifname
) != 0)
90 addr_in
= (struct sockaddr_in
*)p
->ifa_addr
;
91 if (!ifname
&& (p
->ifa_flags
& (IFF_LOOPBACK
| IFF_SLAVE
)))
93 memcpy(&lan_addr
[n_lan_addr
].addr
, &addr_in
->sin_addr
, sizeof(lan_addr
[n_lan_addr
].addr
));
94 if (!inet_ntop(AF_INET
, &addr_in
->sin_addr
, lan_addr
[n_lan_addr
].str
, sizeof(lan_addr
[0].str
)) )
96 DPRINTF(E_ERROR
, L_GENERAL
, "inet_ntop(): %s\n", strerror(errno
));
99 addr_in
= (struct sockaddr_in
*)p
->ifa_netmask
;
100 memcpy(&lan_addr
[n_lan_addr
].mask
, &addr_in
->sin_addr
, sizeof(lan_addr
[n_lan_addr
].mask
));
101 lan_addr
[n_lan_addr
].ifindex
= if_nametoindex(p
->ifa_name
);
102 lan_addr
[n_lan_addr
].snotify
= OpenAndConfSSDPNotifySocket(&lan_addr
[n_lan_addr
]);
103 if (lan_addr
[n_lan_addr
].snotify
>= 0)
105 if (ifname
|| n_lan_addr
>= MAX_LAN_ADDR
)
111 DPRINTF(E_ERROR
, L_GENERAL
, "Network interface %s not found\n", ifname
);
115 int s
= socket(PF_INET
, SOCK_STREAM
, 0);
116 struct sockaddr_in addr
;
122 memset(&ifc
, '\0', sizeof(ifc
));
124 ifc
.ifc_len
= sizeof(buf
);
126 if (ioctl(s
, SIOCGIFCONF
, &ifc
) < 0)
128 DPRINTF(E_ERROR
, L_GENERAL
, "SIOCGIFCONF: %s\n", strerror(errno
));
133 n
= ifc
.ifc_len
/ sizeof(struct ifreq
);
134 for (i
= 0; i
< n
; i
++)
136 ifr
= &ifc
.ifc_req
[i
];
137 if (ifname
&& strcmp(ifr
->ifr_name
, ifname
) != 0)
140 (ioctl(s
, SIOCGIFFLAGS
, ifr
) < 0 || ifr
->ifr_ifru
.ifru_flags
& IFF_LOOPBACK
))
142 if (ioctl(s
, SIOCGIFADDR
, ifr
) < 0)
144 memcpy(&addr
, &(ifr
->ifr_addr
), sizeof(addr
));
145 memcpy(&lan_addr
[n_lan_addr
].addr
, &addr
.sin_addr
, sizeof(lan_addr
[n_lan_addr
].addr
));
146 if (!inet_ntop(AF_INET
, &addr
.sin_addr
, lan_addr
[n_lan_addr
].str
, sizeof(lan_addr
[0].str
)))
148 DPRINTF(E_ERROR
, L_GENERAL
, "inet_ntop(): %s\n", strerror(errno
));
152 if (ioctl(s
, SIOCGIFNETMASK
, ifr
) < 0)
154 memcpy(&addr
, &(ifr
->ifr_addr
), sizeof(addr
));
155 memcpy(&lan_addr
[n_lan_addr
].mask
, &addr
.sin_addr
, sizeof(addr
));
156 lan_addr
[n_lan_addr
].ifindex
= if_nametoindex(ifr
->ifr_name
);
157 lan_addr
[n_lan_addr
].snotify
= OpenAndConfSSDPNotifySocket(&lan_addr
[n_lan_addr
]);
158 if (lan_addr
[n_lan_addr
].snotify
>= 0)
160 if (ifname
|| n_lan_addr
>= MAX_LAN_ADDR
)
164 if (ifname
&& i
== n
)
166 DPRINTF(E_ERROR
, L_GENERAL
, "Network interface %s not found\n", ifname
);
174 getsyshwaddr(char *buf
, int len
)
176 unsigned char mac
[6];
178 #if defined(HAVE_GETIFADDRS) && !defined (__linux__) && !defined (__sun__)
179 struct ifaddrs
*ifap
, *p
;
180 struct sockaddr_in
*addr_in
;
183 if (getifaddrs(&ifap
) != 0)
185 DPRINTF(E_ERROR
, L_GENERAL
, "getifaddrs(): %s\n", strerror(errno
));
188 for (p
= ifap
; p
!= NULL
; p
= p
->ifa_next
)
190 if (p
->ifa_addr
&& p
->ifa_addr
->sa_family
== AF_LINK
)
192 addr_in
= (struct sockaddr_in
*)p
->ifa_addr
;
193 a
= (htonl(addr_in
->sin_addr
.s_addr
) >> 0x18) & 0xFF;
196 #if defined(__linux__)
199 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
202 strncpy(ifr
.ifr_name
, p
->ifa_name
, IFNAMSIZ
);
203 ret
= ioctl(fd
, SIOCGIFHWADDR
, &ifr
);
207 memcpy(mac
, ifr
.ifr_hwaddr
.sa_data
, 6);
209 struct sockaddr_dl
*sdl
;
210 sdl
= (struct sockaddr_dl
*)p
->ifa_addr
;
211 memcpy(mac
, LLADDR(sdl
), sdl
->sdl_alen
);
213 if (MACADDR_IS_ZERO(mac
))
221 struct if_nameindex
*ifaces
, *if_idx
;
225 memset(&mac
, '\0', sizeof(mac
));
226 /* Get the spatially unique node identifier */
227 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
231 ifaces
= if_nameindex();
238 for (if_idx
= ifaces
; if_idx
->if_index
; if_idx
++)
240 strncpyt(ifr
.ifr_name
, if_idx
->if_name
, IFNAMSIZ
);
241 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) < 0)
243 if (ifr
.ifr_ifru
.ifru_flags
& IFF_LOOPBACK
)
245 if (ioctl(fd
, SIOCGIFHWADDR
, &ifr
) < 0)
248 if (MACADDR_IS_ZERO(ifr
.ifr_addr
.sa_data
))
250 memcpy(mac
, ifr
.ifr_addr
.sa_data
, 6);
252 if (MACADDR_IS_ZERO(ifr
.ifr_hwaddr
.sa_data
))
254 memcpy(mac
, ifr
.ifr_hwaddr
.sa_data
, 6);
259 if_freenameindex(ifaces
);
265 sprintf(buf
, "%02x%02x%02x%02x%02x%02x",
266 mac
[0]&0xFF, mac
[1]&0xFF, mac
[2]&0xFF,
267 mac
[3]&0xFF, mac
[4]&0xFF, mac
[5]&0xFF);
269 memmove(buf
, mac
, 6);
275 get_remote_mac(struct in_addr ip_addr
, unsigned char *mac
)
277 struct in_addr arp_ent
;
280 int matches
, hwtype
, flags
;
281 memset(mac
, 0xFF, 6);
283 arp
= fopen("/proc/net/arp", "r");
288 matches
= fscanf(arp
, "%15s 0x%8X 0x%8X %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
289 remote_ip
, &hwtype
, &flags
,
290 &mac
[0], &mac
[1], &mac
[2], &mac
[3], &mac
[4], &mac
[5]);
293 inet_pton(AF_INET
, remote_ip
, &arp_ent
);
294 if (ip_addr
.s_addr
== arp_ent
.s_addr
)
302 memset(mac
, 0xFF, 6);
310 reload_ifaces(int force_notify
)
312 struct in_addr old_addr
[MAX_LAN_ADDR
];
315 memset(&old_addr
, 0xFF, sizeof(old_addr
));
316 for (i
= 0; i
< n_lan_addr
; i
++)
318 memcpy(&old_addr
[i
], &lan_addr
[i
].addr
, sizeof(struct in_addr
));
319 close(lan_addr
[i
].snotify
);
325 getifaddr(runtime_vars
.ifaces
[i
]);
327 } while (i
< MAX_LAN_ADDR
&& runtime_vars
.ifaces
[i
]);
329 for (i
= 0; i
< n_lan_addr
; i
++)
331 for (j
= 0; j
< MAX_LAN_ADDR
; j
++)
333 if (memcmp(&lan_addr
[i
].addr
, &old_addr
[j
], sizeof(struct in_addr
)) == 0)
336 /* Send out startup notifies if it's a new interface, or on SIGHUP */
337 if (force_notify
|| j
== MAX_LAN_ADDR
)
339 DPRINTF(E_INFO
, L_GENERAL
, "Enabling interface %s/%s\n",
340 lan_addr
[i
].str
, inet_ntoa(lan_addr
[i
].mask
));
341 SendSSDPGoodbyes(lan_addr
[i
].snotify
);
342 SendSSDPNotifies(lan_addr
[i
].snotify
, lan_addr
[i
].str
,
343 runtime_vars
.port
, runtime_vars
.notify_interval
);
349 OpenAndConfMonitorSocket(void)
352 struct sockaddr_nl addr
;
356 s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
359 perror("couldn't open NETLINK_ROUTE socket");
363 memset(&addr
, 0, sizeof(addr
));
364 addr
.nl_family
= AF_NETLINK
;
365 addr
.nl_groups
= RTMGRP_IPV4_IFADDR
;
367 ret
= bind(s
, (struct sockaddr
*)&addr
, sizeof(addr
));
370 perror("couldn't bind");
382 ProcessMonitorEvent(int s
)
387 struct nlmsghdr
*nlh
;
390 nlh
= (struct nlmsghdr
*)buf
;
392 len
= recv(s
, nlh
, sizeof(buf
), 0);
395 while ((NLMSG_OK(nlh
, len
)) && (nlh
->nlmsg_type
!= NLMSG_DONE
))
397 if (nlh
->nlmsg_type
== RTM_NEWADDR
||
398 nlh
->nlmsg_type
== RTM_DELADDR
)
402 nlh
= NLMSG_NEXT(nlh
, len
);