diff --git a/backupSession.c b/backupSession.c index 70398b2..7107737 100644 --- a/backupSession.c +++ b/backupSession.c @@ -2013,6 +2013,14 @@ int cwmp_load_saved_session(struct cwmp *cwmp, char **ret, enum backup_loading l break; } } + if(load == CR_IPv6) + { + if(b->type == MXML_ELEMENT && strcmp(b->value.element.name, "connection_request") == 0) + { + *ret = load_child_value(b, "ipv6"); + break; + } + } if(load == CR_PORT) { if(b->type == MXML_ELEMENT && strcmp(b->value.element.name, "connection_request") == 0) diff --git a/cwmp.c b/cwmp.c index 1e27058..b6d2f3f 100644 --- a/cwmp.c +++ b/cwmp.c @@ -32,6 +32,7 @@ struct cwmp cwmp_main = {0}; +int ip_version = 4; LIST_HEAD(list_execute_end_session); int dm_add_end_session(void(*function)(int a, void *d), int action, void *data) @@ -533,7 +534,7 @@ int run_session_end_func (struct session *session) { CWMP_LOG (INFO,"Executing external commands: end session request"); external_init(); - external_simple("end_session", NULL); + external_simple("end_session", NULL, 0); external_exit(); } @@ -541,7 +542,7 @@ int run_session_end_func (struct session *session) { CWMP_LOG (INFO,"Executing factory reset: end session request"); external_init(); - external_simple("factory_reset", NULL); + external_simple("factory_reset", NULL, 0); external_exit(); exit(EXIT_SUCCESS); } @@ -556,7 +557,7 @@ int run_session_end_func (struct session *session) { CWMP_LOG (INFO,"Executing Reboot: end session request"); external_init(); - external_simple("reboot", NULL); + external_simple("reboot", NULL, 0); external_exit(); exit(EXIT_SUCCESS); } diff --git a/dm/dmcommon.c b/dm/dmcommon.c index ed1b2f4..787e4c8 100644 --- a/dm/dmcommon.c +++ b/dm/dmcommon.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "dmcwmp.h" #include "dmuci.h" #include "dmubus.h" @@ -378,10 +379,21 @@ int ipcalc_rev_end(char *ip_str, char *mask_str, char *start_str, char *ipend_st int network_get_ipaddr(char **value, char *iface) { json_object *res; + char *ipv6_value = ""; dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", iface}}, 1, &res); DM_ASSERT(res, *value = ""); json_select(res, "ipv4-address", 0, "address", value, NULL); + json_select(res, "ipv6-address", 0, "address", &ipv6_value, NULL); + + if((*value)[0] == '\0' || ipv6_value[0] == '\0') { + if ((*value)[0] == '\0') + *value = ipv6_value; + } + else if (ip_version == 6) { + *value = ipv6_value; + return 0; + } return 0; } diff --git a/event.c b/event.c index 4cd1843..717e605 100644 --- a/event.c +++ b/event.c @@ -734,21 +734,25 @@ void sotfware_version_value_change(struct cwmp *cwmp, struct transfer_complete * } -void connection_request_ip_value_change(struct cwmp *cwmp) +void connection_request_ip_value_change(struct cwmp *cwmp, int version) { char *bip = NULL; struct event_container *event_container; int error; + char *ip_version = (version == IPv6) ? strdup("ipv6") : strdup("ip"); + char *ip_value = (version == IPv6) ? strdup(cwmp->conf.ipv6) : strdup(cwmp->conf.ip); - error = cwmp_load_saved_session(cwmp, &bip, CR_IP); + error = (version == IPv6) ? cwmp_load_saved_session(cwmp, &bip, CR_IPv6): cwmp_load_saved_session(cwmp, &bip, CR_IP); if(bip == NULL) { - bkp_session_simple_insert_in_parent("connection_request", "ip", cwmp->conf.ip); + bkp_session_simple_insert_in_parent("connection_request", ip_version, ip_value); bkp_session_save(); + FREE(ip_version); + FREE(ip_value); return; } - if (strcmp(bip, cwmp->conf.ip)!=0) + if (strcmp(bip, ip_value)!=0) { pthread_mutex_lock (&(cwmp->mutex_session_queue)); event_container = cwmp_add_event_container (cwmp, EVENT_IDX_4VALUE_CHANGE, ""); @@ -756,15 +760,19 @@ void connection_request_ip_value_change(struct cwmp *cwmp) { FREE(bip); pthread_mutex_unlock (&(cwmp->mutex_session_queue)); + FREE(ip_version); + FREE(ip_value); return; } cwmp_save_event_container (cwmp,event_container); - bkp_session_simple_insert_in_parent("connection_request", "ip", cwmp->conf.ip); + bkp_session_simple_insert_in_parent("connection_request", ip_version, ip_value); bkp_session_save(); pthread_mutex_unlock (&(cwmp->mutex_session_queue)); pthread_cond_signal(&(cwmp->threshold_session_send)); } FREE(bip); + FREE(ip_version); + FREE(ip_value); } void connection_request_port_value_change(struct cwmp *cwmp, int port) diff --git a/external.c b/external.c index 92e8765..26eb7f5 100644 --- a/external.c +++ b/external.c @@ -231,7 +231,7 @@ int external_handle_action(int (*external_handler)(char *msg)) return 0; } -int external_simple(char *command, char *arg) +int external_simple(char *command, char *arg, int c) { DD(INFO,"executing %s request", command); @@ -243,6 +243,7 @@ int external_simple(char *command, char *arg) json_obj_out_add(json_obj_out, "command", command); if (arg) json_obj_out_add(json_obj_out, "arg", arg); + if (c) json_obj_out_add(json_obj_out, "ipv6", "1"); external_write_pipe_output(json_object_to_json_string(json_obj_out)); json_object_put(json_obj_out); diff --git a/http.c b/http.c index d456f8d..3086ccd 100644 --- a/http.c +++ b/http.c @@ -53,6 +53,7 @@ http_client_init(struct cwmp *cwmp) { char *dhcp_dis; char *acs_var_stat; + unsigned char buf[sizeof(struct in6_addr)]; uci_get_value(UCI_DHCP_DISCOVERY_PATH, &dhcp_dis); #ifdef HTTP_CURL if (dhcp_dis && cwmp->retry_count_session > 0 && strcmp(dhcp_dis, "enable") == 0) { @@ -108,6 +109,14 @@ http_client_init(struct cwmp *cwmp) return -1; #endif /* HTTP_ZSTREAM */ +char *ip = NULL; +curl_easy_setopt(curl, CURLOPT_URL, http_c.url); +curl_easy_setopt(curl, CURLOPT_TIMEOUT, HTTP_TIMEOUT); +curl_easy_setopt(curl, CURLOPT_NOBODY, 1); +curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ip); +curl_easy_perform(curl); +int tmp = inet_pton(AF_INET, ip, buf); +ip_version = (tmp == 1) ? 4 : 6; return 0; } @@ -157,6 +166,7 @@ http_get_response(void *buffer, size_t size, size_t rxed, char **msg_in) int http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len,char **msg_in) { + unsigned char buf[sizeof(struct in6_addr)]; #ifdef HTTP_CURL CURLcode res; long http_code = 0; @@ -181,6 +191,7 @@ http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len,char **msg_i curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, HTTP_TIMEOUT); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_NOBODY, 0); switch (cwmp->conf.compression) { case COMP_NONE: break; @@ -240,8 +251,13 @@ http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len,char **msg_i if (!ip_acs || strcmp(ip_acs, ip) != 0) { FREE(ip_acs); ip_acs = strdup(ip); + int tmp = inet_pton(AF_INET, ip, buf); + if (tmp == 1) + tmp = 0; + else + tmp = inet_pton(AF_INET6, ip, buf); external_init(); - external_simple("allow_cr_ip", ip_acs); + external_simple("allow_cr_ip", ip_acs, tmp); external_exit(); } } @@ -390,14 +406,14 @@ http_done: void http_server_init(void) { - struct sockaddr_in server = {0}; + struct sockaddr_in6 server = {0}; unsigned short cr_port; for(;;) { cr_port = (unsigned short) (cwmp_main.conf.connection_request_port); unsigned short i = (DEFAULT_CONNECTION_REQUEST_PORT == cr_port)? 1 : 0; //Create socket - cwmp_main.cr_socket_desc = socket(AF_INET , SOCK_STREAM , 0); + cwmp_main.cr_socket_desc = socket(AF_INET6 , SOCK_STREAM , 0); if (cwmp_main.cr_socket_desc == -1) { CWMP_LOG (ERROR,"Could not open server socket for Connection Requests, Error no is : %d, Error description is : %s", errno, strerror(errno)); @@ -414,11 +430,11 @@ void http_server_init(void) } //Prepare the sockaddr_in structure - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; + server.sin6_family = AF_INET6; + server.sin6_addr=in6addr_any; for(;;i++) { - server.sin_port = htons(cr_port); + server.sin6_port = htons(cr_port); //Bind if( bind(cwmp_main.cr_socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) { @@ -446,7 +462,7 @@ void http_server_listen(void) static time_t restrict_start_time = 0; time_t current_time; bool service_available; - struct sockaddr_in client; + struct sockaddr_in6 client; //Listen listen(cwmp_main.cr_socket_desc , 3); diff --git a/inc/backupSession.h b/inc/backupSession.h index 88d6a2b..4df00b4 100644 --- a/inc/backupSession.h +++ b/inc/backupSession.h @@ -31,6 +31,7 @@ typedef enum backup_loading { ALL, ACS, CR_IP, + CR_IPv6, CR_PORT } backup_loading; diff --git a/inc/cwmp.h b/inc/cwmp.h index 9802dd5..a835019 100644 --- a/inc/cwmp.h +++ b/inc/cwmp.h @@ -180,6 +180,7 @@ typedef struct config { char *cpe_passwd; char *dhcp_url_path; char *ip; + char *ipv6; char *interface; char *ubus_socket; int connection_request_port; @@ -230,6 +231,11 @@ enum enum_session_status { SESSION_SUCCESS }; +enum enum_ip_version { + IPv4 = 4, + IPv6 = 6 +}; + struct deviceid { char *manufacturer; char *oui; @@ -310,6 +316,7 @@ typedef struct execute_end_session { void (*function)(int, void*); } execute_end_session; +extern int ip_version; #define ARRAYSIZEOF(a) (sizeof(a) / sizeof((a)[0])) #define FREE(x) do { free(x); x = NULL; } while (0) @@ -335,7 +342,7 @@ int netlink_init(void); char * mix_get_time(void); char * mix_get_time_of(time_t t_time); void *thread_exit_program (void *v); -void connection_request_ip_value_change(struct cwmp *cwmp); +void connection_request_ip_value_change(struct cwmp *cwmp, int version); void connection_request_port_value_change(struct cwmp *cwmp, int port); void add_dm_parameter_tolist(struct list_head *head, char *param_name, char *param_data, char *param_type); void cwmp_set_end_session (unsigned int end_session_flag); diff --git a/inc/external.h b/inc/external.h index 67171da..9c786e7 100644 --- a/inc/external.h +++ b/inc/external.h @@ -27,7 +27,7 @@ void external_uploadFaultResp (char *fault_code); void external_fetch_uploadFaultResp (char **fault_code); void external_uninstallFaultResp (char *fault_code); void external_fetch_uninstallFaultResp (char **fault); -int external_simple(char *command, char *arg); +int external_simple(char *command, char *arg, int c); int external_download(char *url, char *size, char *type, char *user, char *pass,time_t c); int external_upload(char *url, char *type, char *user, char *pass, char *name); int external_apply(char *action, char *arg,time_t c); diff --git a/netlink.c b/netlink.c index 2cfcedd..39e88e9 100644 --- a/netlink.c +++ b/netlink.c @@ -34,7 +34,9 @@ #include "log.h" static void netlink_new_msg(struct uloop_fd *ufd, unsigned events); +static void netlink_new_msg_v6(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 void freecwmp_netlink_interface(struct nlmsghdr *nlh) { @@ -47,6 +49,8 @@ static void freecwmp_netlink_interface(struct nlmsghdr *nlh) 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); @@ -76,11 +80,33 @@ static void freecwmp_netlink_interface(struct nlmsghdr *nlh) uci_set_state_value(c); free(c); } - connection_request_ip_value_change(&cwmp_main); + connection_request_ip_value_change(&cwmp_main, IPv4); break; } - if (strlen(if_addr) == 0) return; + } 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) @@ -119,6 +145,89 @@ static void netlink_new_msg(struct uloop_fd *ufd, unsigned events) } } +static void netlink_new_msg_v6(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_in6 *)&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 { diff --git a/scripts/icwmp.sh b/scripts/icwmp.sh index e1bd730..39a7128 100644 --- a/scripts/icwmp.sh +++ b/scripts/icwmp.sh @@ -120,6 +120,7 @@ case "$1" in allow_cr_ip) action="allow_cr_ip" __arg1="$2" + __arg2="$3" ;; json_continuous_input) action="json_continuous_input" @@ -361,7 +362,11 @@ handle_action() { local zone_name=`$UCI_GET firewall.$zone.name` [ "$zone_name" = "" ] && return # update iptables rule - sed -i "s,^.*Open ACS port.*,iptables -I zone_${zone_name}_input -p tcp -s $__arg1 --dport $port -j ACCEPT -m comment --comment=\"Open ACS port\",g" /etc/firewall.cwmp + if [ "$__arg2" != "1" ]; then + sed -i "s,^.*iptables.*Open ACS port.*,iptables -I zone_${zone_name}_input -p tcp -s $__arg1 --dport $port -j ACCEPT -m comment --comment=\"Open ACS port\",g" /etc/firewall.cwmp + else + sed -i "s,^.*iptables.*Open ACS port.*,ip6tables -I zone_${zone_name}_input -p tcp -s $__arg1 --dport $port -j ACCEPT -m comment --comment=\"Open ACS port\",g" /etc/firewall.cwmp + fi fw3 reload fi @@ -470,6 +475,7 @@ handle_action() { allow_cr_ip) action="allow_cr_ip" json_get_var __arg1 arg + json_get_var __arg2 ipv6 ;; end) echo "$CWMP_PROMPT" diff --git a/ubus.c b/ubus.c index 6bce042..9645059 100644 --- a/ubus.c +++ b/ubus.c @@ -329,6 +329,9 @@ ubus_init(struct cwmp *cwmp) CWMP_LOG(ERROR,"netlink initialization failed"); } + if (netlink_init_v6()) { + CWMP_LOG(ERROR,"netlink initialization failed"); + } ctx = ubus_connect(cwmp->conf.ubus_socket); if (!ctx) return -1;