diff options
-rw-r--r-- | watchlink/Makefile.am | 2 | ||||
-rw-r--r-- | watchlink/netlink_event.cc | 15 | ||||
-rw-r--r-- | watchlink/netlink_event.hh | 3 | ||||
-rw-r--r-- | watchlink/netlink_linkstatus.cc | 58 | ||||
-rw-r--r-- | watchlink/netlink_listener.cc | 5 | ||||
-rw-r--r-- | watchlink/netlink_listener.hh | 2 | ||||
-rw-r--r-- | watchlink/netlink_send.cc | 174 | ||||
-rw-r--r-- | watchlink/netlink_send.hh | 6 | ||||
-rw-r--r-- | watchlink/netlink_utils.cc | 59 | ||||
-rw-r--r-- | watchlink/netlink_utils.hh | 20 | ||||
-rw-r--r-- | watchlink/watchlink.cc | 2 |
11 files changed, 284 insertions, 62 deletions
diff --git a/watchlink/Makefile.am b/watchlink/Makefile.am index 0a484ee2..798275e5 100644 --- a/watchlink/Makefile.am +++ b/watchlink/Makefile.am @@ -5,4 +5,4 @@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" sbin_PROGRAMS = watchlink -watchlink_SOURCES = watchlink.cc netlink_send.cc netlink_listener.cc netlink_event.cc netlink_linkstatus.cc rl_str_proc.cc +watchlink_SOURCES = watchlink.cc netlink_utils.cc netlink_send.cc netlink_listener.cc netlink_event.cc netlink_linkstatus.cc rl_str_proc.cc diff --git a/watchlink/netlink_event.cc b/watchlink/netlink_event.cc index 286403db..57bb7177 100644 --- a/watchlink/netlink_event.cc +++ b/watchlink/netlink_event.cc @@ -96,7 +96,8 @@ NetlinkEvent::log() * * **/ -NetlinkEventManager::NetlinkEventManager() +NetlinkEventManager::NetlinkEventManager(bool debug) : + _debug(debug) { } @@ -245,16 +246,18 @@ NetlinkEventManager::parse_msg(const struct nlmsghdr *nlHdr) e.set_ifinfomsg(ifInfo); - e.log(); + if (_debug) { + e.log(); + } _coll.push_back(e); } break; case NLMSG_ERROR: { struct nlmsgerr *err = (struct nlmsgerr*) NLMSG_DATA(nlHdr); - syslog(LOG_ERR,"netlink message of type ERROR received: %s",strerror(-err->error)); - cerr << "netlink message of type ERROR received: " ; - cerr << string(strerror(-err->error)) << endl; - syslog(LOG_ERR, strerror(-err->error)); + //drop down to info as this can be caused on startup by downed interfaces that are requested for dump, or attempting to remove routes on downed interface after startup (if they have already been removed). + syslog(LOG_INFO,"netlink message of type ERROR received: %s",strerror(-err->error)); + // cerr << "netlink message of type ERROR received: " ; + // cerr << string(strerror(-err->error)) << endl; } break; case NLMSG_DONE: diff --git a/watchlink/netlink_event.hh b/watchlink/netlink_event.hh index e280de20..f98ce8f4 100644 --- a/watchlink/netlink_event.hh +++ b/watchlink/netlink_event.hh @@ -196,7 +196,7 @@ public: public: //methods friend std::ostream & operator<< (std::ostream &, const NetlinkEvent &); - NetlinkEventManager(); + NetlinkEventManager(bool debug); ~NetlinkEventManager(); @@ -214,6 +214,7 @@ private: //methods private: //variables NLEventColl _coll; + bool _debug; }; diff --git a/watchlink/netlink_linkstatus.cc b/watchlink/netlink_linkstatus.cc index e1aa78dc..949b8a71 100644 --- a/watchlink/netlink_linkstatus.cc +++ b/watchlink/netlink_linkstatus.cc @@ -33,6 +33,7 @@ #include "rl_str_proc.hh" #include "netlink_send.hh" #include "netlink_event.hh" +#include "netlink_utils.hh" #include "netlink_linkstatus.hh" @@ -174,13 +175,30 @@ NetlinkLinkStatus::process_going_up(const NetlinkEvent &event) int ifindex = strtoul(tokens.get(0).c_str(),NULL,10); uint32_t local_addr = strtoul(tokens.get(1).c_str(),NULL,10); - uint32_t addr = strtoul(tokens.get(2).c_str(),NULL,10); + // uint32_t addr = strtoul(tokens.get(2).c_str(),NULL,10); int mask_len = strtoul(tokens.get(3).c_str(),NULL,10); + bool err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, local_addr, 32, RTM_NEWROUTE, RT_TABLE_LOCAL, RTN_LOCAL, RT_SCOPE_HOST); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up"); + } + //COMPUTE FIRST ADDRESS + uint32_t first_addr = ipv4_first_addr(local_addr, mask_len); + err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, first_addr, 32, RTM_NEWROUTE, RT_TABLE_LOCAL, RTN_BROADCAST, RT_SCOPE_LINK); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up"); + } + //COMPUTE LAST ADDRESS + uint32_t last_addr = ipv4_broadcast_addr(local_addr, mask_len); + err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, last_addr, 32, RTM_NEWROUTE, RT_TABLE_LOCAL, RTN_BROADCAST, RT_SCOPE_LINK); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up"); + } + //reinsert addresses to interface - if (_nl_send.send_set(_send_sock, ifindex, local_addr, addr, mask_len, RTM_NEWADDR)) { + err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, first_addr, mask_len, RTM_NEWROUTE, RT_TABLE_MAIN, RTN_UNICAST, RT_SCOPE_LINK); + if (err) { syslog(LOG_INFO,"NetlinkLinkStatus::process_up(), failure in setting interface back to up"); - // cerr << "NetlinkLinkStatus::process_up(), failure in setting interface back to up" << endl; } } @@ -226,24 +244,44 @@ NetlinkLinkStatus::process_down(const NetlinkEvent &event) return -1; } + int ifindex = event.get_index(); + uint32_t local_addr = event.get_local_addr().get(); + int mask_len = event.get_mask_len(); + //create file on system //CRAJ--NEED TO HAVE THIS BE FROM A COLLECTION??? DEPENDS ON FORMAT OF NETLINK MSG - sprintf(buf,"%d",event.get_index()); + sprintf(buf,"%d",ifindex); string line = string(buf) + ","; - sprintf(buf,"%d",event.get_local_addr().get()); + sprintf(buf,"%d",local_addr); line += string(buf) + ","; sprintf(buf,"%d",event.get_addr().get()); line += string(buf) + ","; - sprintf(buf,"%d",event.get_mask_len()); + sprintf(buf,"%d",mask_len); line += string(buf) + "\n"; fputs(line.c_str(),fp); + + uint32_t first_addr = ipv4_first_addr(local_addr, mask_len); + //reinsert addresses to interface + bool err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, first_addr, mask_len, RTM_DELROUTE, RT_TABLE_MAIN, -1,-1); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down"); + } + uint32_t last_addr = ipv4_broadcast_addr(local_addr, mask_len); + err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, last_addr, 32, RTM_DELROUTE, RT_TABLE_LOCAL, -1,-1); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down"); + } + + err = _nl_send.send_set_route(_send_sock, ifindex, first_addr, first_addr, 32, RTM_DELROUTE, RT_TABLE_LOCAL, -1,-1); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down"); + } - //pull interface addresses - if (_nl_send.send_set(_send_sock, event.get_index(), event.get_local_addr().get(), event.get_addr().get(), event.get_mask_len(), RTM_DELADDR)) { - fclose(fp); - return -1; + err = _nl_send.send_set_route(_send_sock, ifindex, local_addr, local_addr, 32, RTM_DELROUTE, RT_TABLE_LOCAL, -1,-1); + if (err) { + syslog(LOG_INFO,"NetlinkLinkStatus::process_down(), failure in setting interface down"); } fclose(fp); diff --git a/watchlink/netlink_listener.cc b/watchlink/netlink_listener.cc index 47fc154f..cfc90fd3 100644 --- a/watchlink/netlink_listener.cc +++ b/watchlink/netlink_listener.cc @@ -51,9 +51,10 @@ using namespace std; * * **/ -NetlinkListener::NetlinkListener() : +NetlinkListener::NetlinkListener(bool debug) : _fd(-1), - _is_multipart_message_read(false) + _is_multipart_message_read(false), + _nl_event_mgr(debug) { } diff --git a/watchlink/netlink_listener.hh b/watchlink/netlink_listener.hh index b73130fd..72be844b 100644 --- a/watchlink/netlink_listener.hh +++ b/watchlink/netlink_listener.hh @@ -35,7 +35,7 @@ class NetlinkListener { public: //methods - NetlinkListener(); + NetlinkListener(bool debug); ~NetlinkListener(); /* diff --git a/watchlink/netlink_send.cc b/watchlink/netlink_send.cc index 656eb5d9..d48f2abb 100644 --- a/watchlink/netlink_send.cc +++ b/watchlink/netlink_send.cc @@ -30,6 +30,7 @@ #include <linux/types.h> #include <sys/types.h> #include <sys/socket.h> +#include <linux/netlink.h> #include <linux/rtnetlink.h> #include <syslog.h> @@ -37,12 +38,11 @@ #include <string> #include <iostream> +#include "netlink_utils.hh" #include "netlink_send.hh" using namespace std; -in_addr_t -ipv4_broadcast_addr (in_addr_t hostaddr, int masklen); /** * @@ -86,12 +86,16 @@ NetlinkSend::send_set(int sock, int ifindex, uint32_t local_addr, uint32_t addr, if (_debug) { struct in_addr in; in.s_addr = local_addr; - char *buf = inet_ntoa(in); - cout << "NetlinkSend::send_set(): " << type << ", " << buf << "/" << mask_len; + char *lbuf = inet_ntoa(in); in.s_addr = addr; - buf = inet_ntoa(in); - cout << ", to this address: " << buf << ", on interface: " << ifindex << endl; + char *buf = inet_ntoa(in); + + char sbuf[1024]; + sprintf(sbuf, "NetlinkSend::send_set(): %d, %s/%d, to this address: %s, on interface: %d",type,buf,mask_len,lbuf,ifindex); + cout << sbuf << endl; + + syslog(LOG_INFO,sbuf); } memset(&req, 0, sizeof(req)); @@ -106,10 +110,10 @@ NetlinkSend::send_set(int sock, int ifindex, uint32_t local_addr, uint32_t addr, req.ifa.ifa_prefixlen = mask_len; // addr = htonl( addr ); - addattr_l(&req.n, sizeof(req), IFA_LOCAL, &local_addr, sizeof(addr) ); + addattr_l(&req.n, sizeof(req), IFA_LOCAL, &local_addr, sizeof(local_addr) ); in_addr_t broadcast_addr = ipv4_broadcast_addr(local_addr,mask_len); - addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &broadcast_addr, sizeof(addr) ); + addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &broadcast_addr, sizeof(broadcast_addr) ); if (addr != -1 && local_addr != addr) { addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &addr, sizeof(addr) ); @@ -133,6 +137,108 @@ NetlinkSend::send_set(int sock, int ifindex, uint32_t local_addr, uint32_t addr, * **/ int +NetlinkSend::send_set_route(int sock, int ifindex, uint32_t local_addr, uint32_t dst_addr, int mask_len, int type, int table, int rtn_type, int rt_scope) +{ + int ret; + struct sockaddr_nl snl; + struct { + struct nlmsghdr n; + struct rtmsg rt_message; + char buf[8192]; + } req; + req.rt_message.rtm_table = 0; + req.rt_message.rtm_protocol = 0; + req.rt_message.rtm_scope = 0; + req.rt_message.rtm_type = 0; + req.rt_message.rtm_src_len = 0; + req.rt_message.rtm_dst_len = 0; + req.rt_message.rtm_tos = 0; + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + /* Check netlink socket. */ + if (sock < 0) { + syslog(LOG_ERR,"sock is not active, exiting"); + cerr << "sock is not active, exiting" << endl; + return -1; + } + + if (_debug) { + struct in_addr in; + in.s_addr = local_addr; + char *lbuf = inet_ntoa(in); + + in.s_addr = dst_addr; + char *buf = inet_ntoa(in); + + char sbuf[1024]; + sprintf(sbuf, "NetlinkSend::send_set_route(): %d, %s/%d, to this address: %s, on interface: %d, for this table: ",type,buf,mask_len,lbuf,ifindex,table); + cout << sbuf << endl; + + syslog(LOG_INFO,sbuf); + } + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + if (type == RTM_NEWROUTE) { + req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + } + else { + req.n.nlmsg_flags = NLM_F_REQUEST; + } + req.n.nlmsg_pid = getpid(); + req.n.nlmsg_type = type; + req.n.nlmsg_seq = time(NULL); + + req.rt_message.rtm_family = AF_INET; + req.rt_message.rtm_dst_len = mask_len; + req.rt_message.rtm_table = table; + if (type == RTM_NEWROUTE) { + req.rt_message.rtm_protocol = RTPROT_KERNEL; + if (rt_scope != -1) { + req.rt_message.rtm_scope = rt_scope;//RT_SCOPE_HOST; //will need to pass this in to get RT_SCOPE_HOST + } + if (rtn_type != -1) { + req.rt_message.rtm_type = rtn_type;//RTN_LOCAL; + } + } + else { + req.rt_message.rtm_scope = RT_SCOPE_NOWHERE; + req.rt_message.rtm_type = RTN_UNSPEC; + } + + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &local_addr, sizeof(local_addr)); + addattr_l(&req.n, sizeof(req), RTA_DST, &dst_addr, sizeof(dst_addr)); + addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); + + if (_debug) { + cout << "NetlinkSend::send_set_route():" << endl; + cout << " interface: " << ifindex << endl; + cout << " type: " << string(req.n.nlmsg_type == RTM_NEWROUTE ? string("RTM_NEWROUTE") : string("RTM_DELROUTE")) << endl; + cout << " flags: " << req.n.nlmsg_flags << endl; + cout << " protocol: " << int(req.rt_message.rtm_protocol) << endl; + cout << " scope: " << int(req.rt_message.rtm_scope) << endl; + cout << " addr(s): " << local_addr << ", " << dst_addr << ", " << mask_len << ", " << int(req.rt_message.rtm_dst_len) << endl; + cout << endl; + } + + ret = sendto (sock, (void*) &req, sizeof req, 0, + (struct sockaddr*) &snl, sizeof snl); + if (ret < 0) { + syslog(LOG_ERR,"netlink_send_route failed on send: %d, %d",ret,errno); + cerr << "netlink_send_route failed on send: " << ret << ", " << errno << endl; + return -1; + } + return 0; +} + +/** + * + * + **/ +int NetlinkSend::send_get(int sock, int type, int ifindex) { int ret; @@ -150,6 +256,13 @@ NetlinkSend::send_get(int sock, int type, int ifindex) return -1; } + if (_debug) { + char sbuf[1024]; + sprintf(sbuf,"NetlinkSend::send_get(): type: %d, ifindex: %d",type,ifindex); + cout << sbuf << endl; + syslog(LOG_INFO,sbuf); + } + memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); @@ -203,41 +316,22 @@ NetlinkSend::addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int return 0; } -/* Maskbit. */ -static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, - 0xf8, 0xfc, 0xfe, 0xff}; - -/* Convert masklen into IP address's netmask. */ -void -masklen2ip (int masklen, struct in_addr *netmask) +int +NetlinkSend::addattr32(struct nlmsghdr *n, int maxlen, int type, int data) { - u_char *pnt; - int bit; - int offset; + int len; + struct rtattr *rta; - memset (netmask, 0, sizeof (struct in_addr)); - pnt = (unsigned char *) netmask; - - offset = masklen / 8; - bit = masklen % 8; - - while (offset--) - *pnt++ = 0xff; + len = RTA_LENGTH (4); - if (bit) - *pnt = maskbit[bit]; -} + if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) + return -1; + rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len)); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), &data, 4); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; -in_addr_t -ipv4_broadcast_addr (in_addr_t hostaddr, int masklen) -{ - struct in_addr mask; - - masklen2ip (masklen, &mask); - return (masklen != 32-1) ? - /* normal case */ - (hostaddr | ~mask.s_addr) : - /* special case for /31 */ - (hostaddr ^ ~mask.s_addr); + return 0; } diff --git a/watchlink/netlink_send.hh b/watchlink/netlink_send.hh index b653f7b7..e359ea7e 100644 --- a/watchlink/netlink_send.hh +++ b/watchlink/netlink_send.hh @@ -40,10 +40,16 @@ public: int send_set(int sock, int ifindex, uint32_t local_addr, uint32_t addr, int mask_len, int type); + int + send_set_route(int sock, int ifindex, uint32_t local_addr, uint32_t dst_addr, int mask_len, int type, int table, int rtn_type, int rt_scope); + private: int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen); + int + addattr32(struct nlmsghdr *n, int maxlen, int type, int data); + private: bool _debug; diff --git a/watchlink/netlink_utils.cc b/watchlink/netlink_utils.cc new file mode 100644 index 00000000..18a4b3ff --- /dev/null +++ b/watchlink/netlink_utils.cc @@ -0,0 +1,59 @@ +#include <errno.h> +#include <string.h> +#include <arpa/inet.h> +#include <linux/types.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <linux/rtnetlink.h> +#include <syslog.h> + +#include "netlink_utils.hh" + + +/* Maskbit. */ +static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff}; + +/* Convert masklen into IP address's netmask. */ +void +masklen2ip (int masklen, struct in_addr *netmask) +{ + u_char *pnt; + int bit; + int offset; + + memset (netmask, 0, sizeof (struct in_addr)); + pnt = (unsigned char *) netmask; + + offset = masklen / 8; + bit = masklen % 8; + + while (offset--) + *pnt++ = 0xff; + + if (bit) + *pnt = maskbit[bit]; +} + + +in_addr_t +ipv4_broadcast_addr (in_addr_t hostaddr, int masklen) +{ + struct in_addr mask; + + masklen2ip (masklen, &mask); + return (masklen != 32-1) ? + /* normal case */ + (hostaddr | ~mask.s_addr) : + /* special case for /31 */ + (hostaddr ^ ~mask.s_addr); +} + +in_addr_t +ipv4_first_addr (in_addr_t hostaddr, int masklen) +{ + struct in_addr mask; + masklen2ip (masklen, &mask); + return (hostaddr & mask.s_addr); +} + diff --git a/watchlink/netlink_utils.hh b/watchlink/netlink_utils.hh new file mode 100644 index 00000000..a1be920a --- /dev/null +++ b/watchlink/netlink_utils.hh @@ -0,0 +1,20 @@ +#ifndef __NETLINK_UTILS_HH__ +#define __NETLINK_UTILS_HH__ + +#include <arpa/inet.h> +#include <linux/types.h> +#include <sys/types.h> +#include <sys/socket.h> + + +in_addr_t +ipv4_broadcast_addr (in_addr_t hostaddr, int masklen); + +void +masklen2ip (int masklen, struct in_addr *netmask); + +in_addr_t +ipv4_first_addr (in_addr_t hostaddr, int masklen); + + +#endif //__NETLINK_UTILS_HH__ diff --git a/watchlink/watchlink.cc b/watchlink/watchlink.cc index eb0394ad..24218824 100644 --- a/watchlink/watchlink.cc +++ b/watchlink/watchlink.cc @@ -161,7 +161,7 @@ main(int argc, char* const argv[]) } NetlinkSend nl_send(debug); - NetlinkListener nl_listener; + NetlinkListener nl_listener(debug); //add check here to ensure only one watchlink process |