/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Copyright (C) 2013-2019 iopsys Software Solutions AB * Author Mohamed Kallel * Author Ahmed Zribi * Copyright (C) 2011-2012 Luka Perkov * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cwmp.h" #include "http.h" #include "log.h" #include "config.h" static int itfcmp(char *itf1, char *itf2); static void netlink_new_msg(struct uloop_fd *ufd, unsigned events); static struct uloop_fd netlink_event = { .cb = netlink_new_msg }; static struct uloop_fd netlink_event_v6 = { .cb = netlink_new_msg }; static int itfcmp(char *itf1, char *itf2) { int index = 0; int status = 1; char *str = NULL; char *buf1 = NULL; char *buf2 = NULL; if(itf1[0] == '\0') goto end; str = strchr(itf1, '.'); if(str == NULL) goto end; index = (int)(str - itf1); if(!index) goto end; buf1 = malloc(index); strncpy(buf1, itf1, index); if(!buf1) goto end; buf1[index] = '\0'; if(itf2[0] == '\0') goto end; str = strchr(itf2, '.'); if(str == NULL) goto end; index = (int)(str - itf2); if(!index) goto end; buf2 = malloc(index); if(!buf2) goto end; buf2[index] = '\0'; strncpy(buf2, itf1, index); if(strcmp(buf1, buf2) == 0) status = 0; end: if(buf1) free(buf1); if(buf2) free(buf2); return status; } static void freecwmp_netlink_interface(struct nlmsghdr *nlh) { struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh); struct rtattr *rth = IFA_RTA(ifa); int rtl = IFA_PAYLOAD(nlh); char if_name[IFNAMSIZ], if_addr[INET_ADDRSTRLEN]; char *c; memset(&if_name, 0, sizeof(if_name)); memset(&if_addr, 0, sizeof(if_addr)); char pradd_v6[128]; if(ifa->ifa_family == AF_INET) { //CASE IPv4 while (rtl && RTA_OK(rth, rtl)) { if (rth->rta_type != IFA_LOCAL) { rth = RTA_NEXT(rth, rtl); continue; } uint32_t addr = htonl(* (uint32_t *)RTA_DATA(rth)); if (htonl(13) == 13) { // running on big endian system } else { // running on little endian system addr = __builtin_bswap32(addr); } if_indextoname(ifa->ifa_index, if_name); if (itfcmp(cwmp_main.conf.interface, if_name)) { rth = RTA_NEXT(rth, rtl); continue; } inet_ntop(AF_INET, &(addr), if_addr, INET_ADDRSTRLEN); if (cwmp_main.conf.ip) FREE(cwmp_main.conf.ip); cwmp_main.conf.ip = strdup(if_addr); if (asprintf(&c,"cwmp.cpe.ip=%s",cwmp_main.conf.ip) != -1) { uci_set_state_value(c); free(c); } connection_request_ip_value_change(&cwmp_main, IPv4); break; } } else { //CASE IPv6 while (rtl && RTA_OK(rth, rtl)) { if (rth->rta_type != IFA_ADDRESS || ifa->ifa_scope == RT_SCOPE_LINK) { rth = RTA_NEXT(rth, rtl); continue; } inet_ntop(AF_INET6, RTA_DATA(rth), pradd_v6, sizeof(pradd_v6)); if_indextoname(ifa->ifa_index, if_name); if (strncmp(cwmp_main.conf.interface, if_name, IFNAMSIZ)) { rth = RTA_NEXT(rth, rtl); continue; } if (cwmp_main.conf.ipv6) FREE(cwmp_main.conf.ipv6); cwmp_main.conf.ipv6 = strdup(pradd_v6); if (asprintf(&c,"cwmp.cpe.ipv6=%s",cwmp_main.conf.ipv6) != -1) { uci_set_state_value(c); free(c); } connection_request_ip_value_change(&cwmp_main, IPv6); break; } } } static void netlink_new_msg(struct uloop_fd *ufd, unsigned events) { struct nlmsghdr *nlh; char buffer[BUFSIZ]; int msg_size; memset(&buffer, 0, sizeof(buffer)); nlh = (struct nlmsghdr *)buffer; if ((msg_size = recv(ufd->fd, nlh, BUFSIZ, 0)) == -1) { CWMP_LOG(ERROR,"error receiving netlink message"); return; } while (msg_size > sizeof(*nlh)) { int len = nlh->nlmsg_len; int req_len = len - sizeof(*nlh); if (req_len < 0 || len > msg_size) { CWMP_LOG(ERROR,"error reading netlink message"); return; } if (!NLMSG_OK(nlh, msg_size)) { CWMP_LOG(ERROR,"netlink message is not NLMSG_OK"); return; } if (nlh->nlmsg_type == RTM_NEWADDR) freecwmp_netlink_interface(nlh); msg_size -= NLMSG_ALIGN(len); nlh = (struct nlmsghdr*)((char*)nlh + NLMSG_ALIGN(len)); } } int netlink_init_v6(void) { struct { struct nlmsghdr hdr; struct ifaddrmsg msg; } req; struct sockaddr_nl addr; int sock[2]; memset(&addr, 0, sizeof(addr)); memset(&req, 0, sizeof(req)); if ((sock[0] = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { CWMP_LOG(ERROR,"couldn't open NETLINK_ROUTE socket"); return -1; } addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV6_IFADDR; if ((bind(sock[0], (struct sockaddr *)&addr, sizeof(addr))) == -1) { CWMP_LOG(ERROR,"couldn't bind netlink socket"); return -1; } netlink_event_v6.fd = sock[0]; uloop_fd_add(&netlink_event_v6, ULOOP_READ | ULOOP_EDGE_TRIGGER); if ((sock[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1) { CWMP_LOG(ERROR,"couldn't open NETLINK_ROUTE socket"); return -1; } req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; req.hdr.nlmsg_type = RTM_GETADDR; req.msg.ifa_family = AF_INET6; if ((send(sock[1], &req, req.hdr.nlmsg_len, 0)) == -1) { CWMP_LOG(ERROR,"couldn't send netlink socket"); return -1; } struct uloop_fd dummy_event = { .fd = sock[1] }; netlink_new_msg(&dummy_event, 0); return 0; } int netlink_init(void) { struct { struct nlmsghdr hdr; struct ifaddrmsg msg; } req; struct sockaddr_nl addr; int sock[2]; memset(&addr, 0, sizeof(addr)); memset(&req, 0, sizeof(req)); if ((sock[0] = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { CWMP_LOG(ERROR,"couldn't open NETLINK_ROUTE socket"); return -1; } addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV4_IFADDR; if ((bind(sock[0], (struct sockaddr *)&addr, sizeof(addr))) == -1) { CWMP_LOG(ERROR,"couldn't bind netlink socket"); return -1; } netlink_event.fd = sock[0]; uloop_fd_add(&netlink_event, ULOOP_READ | ULOOP_EDGE_TRIGGER); if ((sock[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1) { CWMP_LOG(ERROR,"couldn't open NETLINK_ROUTE socket"); return -1; } req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; req.hdr.nlmsg_type = RTM_GETADDR; req.msg.ifa_family = AF_INET; if ((send(sock[1], &req, req.hdr.nlmsg_len, 0)) == -1) { CWMP_LOG(ERROR,"couldn't send netlink socket"); return -1; } struct uloop_fd dummy_event = { .fd = sock[1] }; netlink_new_msg(&dummy_event, 0); return 0; }