1/* $Id: ifacewatcher.c,v 1.8 2014/04/18 08:23:51 nanard Exp $ */
2/* Project MiniUPnP
3 * web : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2011 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 <sys/types.h>
11#include <sys/time.h>
12#include <sys/socket.h>
13#include <net/if.h>
14#include <net/route.h>
15#include <syslog.h>
16#include <signal.h>
17
18#define	SALIGN	(sizeof(long) - 1)
19#define	SA_RLEN(sa)	(SA_LEN(sa) ? ((SA_LEN(sa) + SALIGN) & ~SALIGN) : (SALIGN + 1))
20
21#include "../upnputils.h"
22#include "../upnpglobalvars.h"
23
24extern volatile sig_atomic_t should_send_public_address_change_notif;
25
26int
27OpenAndConfInterfaceWatchSocket(void)
28{
29	int s;
30
31	/*s = socket(PF_ROUTE, SOCK_RAW, AF_INET);*/
32	s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
33/* The family parameter may be AF_UNSPEC which will provide routing informa-
34 * tion for all address families, or can be restricted to a specific address
35 * family by specifying which one is desired.  There can be more than one
36 * routing socket open per system. */
37	if(s < 0) {
38		syslog(LOG_ERR, "OpenAndConfInterfaceWatchSocket socket: %m");
39	}
40	return s;
41}
42
43void
44ProcessInterfaceWatchNotify(int s)
45{
46	char buf[4096];
47	ssize_t len;
48	char tmp[64];
49	struct rt_msghdr * rtm;
50	struct if_msghdr * ifm;
51	struct ifa_msghdr * ifam;
52#ifdef RTM_IFANNOUNCE
53	struct if_announcemsghdr * ifanm;
54#endif
55	char * p;
56	struct sockaddr * sa;
57	unsigned int ext_if_name_index = 0;
58
59	len = recv(s, buf, sizeof(buf), 0);
60	if(len < 0) {
61		syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m");
62		return;
63	}
64	if(ext_if_name) {
65		ext_if_name_index = if_nametoindex(ext_if_name);
66	}
67	rtm = (struct rt_msghdr *)buf;
68	syslog(LOG_DEBUG, "%u rt_msg : msglen=%d version=%d type=%d", (unsigned)len,
69	       rtm->rtm_msglen, rtm->rtm_version, rtm->rtm_type);
70	switch(rtm->rtm_type) {
71	case RTM_IFINFO:	/* iface going up/down etc. */
72		ifm = (struct if_msghdr *)buf;
73		syslog(LOG_DEBUG, " RTM_IFINFO: addrs=%x flags=%x index=%hu",
74		       ifm->ifm_addrs, ifm->ifm_flags, ifm->ifm_index);
75		break;
76	case RTM_ADD:	/* Add Route */
77		syslog(LOG_DEBUG, " RTM_ADD");
78		break;
79	case RTM_DELETE:	/* Delete Route */
80		syslog(LOG_DEBUG, " RTM_DELETE");
81		break;
82	case RTM_CHANGE:	/* Change Metrics or flags */
83		syslog(LOG_DEBUG, " RTM_CHANGE");
84		break;
85	case RTM_GET:	/* Report Metrics */
86		syslog(LOG_DEBUG, " RTM_GET");
87		break;
88#ifdef RTM_IFANNOUNCE
89	case RTM_IFANNOUNCE:	/* iface arrival/departure */
90		ifanm = (struct if_announcemsghdr *)buf;
91		syslog(LOG_DEBUG, " RTM_IFANNOUNCE: index=%hu what=%hu ifname=%s",
92		       ifanm->ifan_index, ifanm->ifan_what, ifanm->ifan_name);
93		break;
94#endif
95#ifdef RTM_IEEE80211
96	case RTM_IEEE80211:	/* IEEE80211 wireless event */
97		syslog(LOG_DEBUG, " RTM_IEEE80211");
98		break;
99#endif
100	case RTM_NEWADDR:	/* address being added to iface */
101		ifam = (struct ifa_msghdr *)buf;
102		syslog(LOG_DEBUG, " RTM_NEWADDR: addrs=%x flags=%x index=%hu",
103		       ifam->ifam_addrs, ifam->ifam_flags, ifam->ifam_index);
104		p = buf + sizeof(struct ifa_msghdr);
105		while(p < buf + len) {
106			sa = (struct sockaddr *)p;
107			sockaddr_to_string(sa, tmp, sizeof(tmp));
108			syslog(LOG_DEBUG, "  %s", tmp);
109			p += SA_RLEN(sa);
110		}
111		if(ifam->ifam_index == ext_if_name_index) {
112			should_send_public_address_change_notif = 1;
113		}
114		break;
115	case RTM_DELADDR:	/* address being removed from iface */
116		ifam = (struct ifa_msghdr *)buf;
117		if(ifam->ifam_index == ext_if_name_index) {
118			should_send_public_address_change_notif = 1;
119		}
120		break;
121	default:
122		syslog(LOG_DEBUG, "unprocessed RTM message type=%d", rtm->rtm_type);
123	}
124}
125
126