diff options
author | Martin Willi <martin@strongswan.org> | 2007-06-15 13:23:18 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-06-15 13:23:18 +0000 |
commit | 08a8f4496ff58c74631da1b7145145d9e9b56ccc (patch) | |
tree | 83007743fbc4ee1a583aaf2d762149c076da7019 | |
parent | 02b3ec0a10482feabdf1017f1693deeabbfcb245 (diff) | |
download | strongswan-08a8f4496ff58c74631da1b7145145d9e9b56ccc.tar.bz2 strongswan-08a8f4496ff58c74631da1b7145145d9e9b56ccc.tar.xz |
implemented more flexible iterator hook API
kernel interface handles interface changes and updates address list
-rwxr-xr-x | src/charon/control/interfaces/stroke_interface.c | 3 | ||||
-rw-r--r-- | src/charon/kernel/kernel_interface.c | 540 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 8 | ||||
-rw-r--r-- | src/libstrongswan/utils/iterator.h | 42 | ||||
-rw-r--r-- | src/libstrongswan/utils/linked_list.c | 59 |
5 files changed, 418 insertions, 234 deletions
diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 9bae90832..09846fe59 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -1216,8 +1216,7 @@ static void stroke_status(stroke_msg_t *msg, FILE *out, bool all) charon->scheduler->get_job_load(charon->scheduler)); iterator = charon->kernel_interface->create_address_iterator( charon->kernel_interface); - fprintf(out, "Listening on %d IP addresses:\n", - iterator->get_count(iterator)); + fprintf(out, "Listening IP addresses:\n"); while (iterator->iterate(iterator, (void**)&host)) { fprintf(out, " %H\n", host); diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index f00cbab81..8212841df 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -242,29 +242,32 @@ static void vip_entry_destroy(vip_entry_t *this) free(this); } -typedef struct address_entry_t address_entry_t; +typedef struct interface_entry_t interface_entry_t; /** - * an address found on the system, containg address and interface info + * A network interface on this system, containing addresses */ -struct address_entry_t { - - /** address of this entry */ - host_t *host; +struct interface_entry_t { /** interface index */ int ifindex; - /** name of the index */ + /** name of the interface */ char ifname[IFNAMSIZ]; + + /** interface flags, as in netdevice(7) SIOCGIFFLAGS */ + u_int flags; + + /** list of addresses as host_t */ + linked_list_t *addresses; }; /** - * destroy an address entry + * destroy an interface entry */ -static void address_entry_destroy(address_entry_t *this) +static void interface_entry_destroy(interface_entry_t *this) { - this->host->destroy(this->host); + this->addresses->destroy_offset(this->addresses, offsetof(host_t, destroy)); free(this); } @@ -280,14 +283,14 @@ struct private_kernel_interface_t { kernel_interface_t public; /** - * List of installed policies (kernel_entry_t) + * mutex to lock access to the various lists */ - linked_list_t *policies; + pthread_mutex_t mutex; /** - * Mutex locks access to policies + * List of installed policies (kernel_entry_t) */ - pthread_mutex_t policies_mutex; + linked_list_t *policies; /** * List of installed virtual IPs. (vip_entry_t) @@ -295,26 +298,26 @@ struct private_kernel_interface_t { linked_list_t *vips; /** - * Mutex to lock access to vips. - */ - pthread_mutex_t vips_mutex; - - /** - * Cached list of IP adresses (address_entry_t) + * Cached list of interfaces and its adresses (interface_entry_t) */ - linked_list_t *addrs; + linked_list_t *interfaces; /** - * Mutex to lock access to addr. + * iterator used in hook() */ - pthread_mutex_t addrs_mutex; + iterator_t *hiter; /** - * job receiving xfrm events + * job receiving netlink events */ callback_job_t *job; /** + * current sequence number for netlink request + */ + int seq; + + /** * Netlink xfrm socket (IPsec) */ int socket_xfrm; @@ -517,92 +520,110 @@ static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hd } /** - * process a RTM_NEWADDR from kernel + * process RTM_NEWLINK/RTM_DELLINK from kernel */ -static void process_newaddr(private_kernel_interface_t *this, - struct nlmsghdr *hdr, bool initial) +static void process_link(private_kernel_interface_t *this, + struct nlmsghdr *hdr, bool event) { - struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); - struct rtattr *rta = IFA_RTA(msg); - size_t rtasize = IFA_PAYLOAD (hdr); - host_t *host = NULL; + struct ifinfomsg* msg = (struct ifinfomsg*)(NLMSG_DATA(hdr)); + struct rtattr *rta = IFLA_RTA(msg); + size_t rtasize = IFLA_PAYLOAD (hdr); + iterator_t *iterator; + interface_entry_t *current, *entry = NULL; char *name = NULL; - chunk_t local = chunk_empty, address = chunk_empty; - + while(RTA_OK(rta, rtasize)) { switch (rta->rta_type) { - case IFA_LOCAL: - local.ptr = RTA_DATA(rta); - local.len = RTA_PAYLOAD(rta); - break; - case IFA_ADDRESS: - address.ptr = RTA_DATA(rta); - address.len = RTA_PAYLOAD(rta); - break; - case IFA_LABEL: + case IFLA_IFNAME: name = RTA_DATA(rta); break; } rta = RTA_NEXT(rta, rtasize); } - - /* For PPP interfaces, we need the IFA_LOCAL address, - * IFA_ADDRESS is the peers address. But IFA_LOCAL is - * not included in all cases, so fallback to IFA_ADDRESS. */ - if (local.ptr) - { - host = host_create_from_chunk(msg->ifa_family, local, 0); - } - else if (address.ptr) + if (!name) { - host = host_create_from_chunk(msg->ifa_family, address, 0); + name = "(unknown)"; } - if (host) + switch (hdr->nlmsg_type) { - address_entry_t *entry; - - entry = malloc_thing(address_entry_t); - entry->host = host; - entry->ifindex = msg->ifa_index; - if (name) + case RTM_NEWLINK: { + if (msg->ifi_flags & IFF_LOOPBACK) + { /* ignore loopback interfaces */ + break; + } + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (current->ifindex == msg->ifi_index) + { + entry = current; + break; + } + } + if (!entry) + { + entry = malloc_thing(interface_entry_t); + entry->ifindex = msg->ifi_index; + entry->flags = 0; + entry->addresses = linked_list_create(); + this->interfaces->insert_last(this->interfaces, entry); + } memcpy(entry->ifname, name, IFNAMSIZ); + entry->ifname[IFNAMSIZ-1] = '\0'; + if (event) + { + if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP)) + { + DBG1(DBG_KNL, "interface %s activated", name); + } + if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP)) + { + DBG1(DBG_KNL, "interface %s deactivated", name); + } + } + entry->flags = msg->ifi_flags; + iterator->destroy(iterator); + break; } - else - { - strcpy(entry->ifname, "(unknown)"); - } - - if (initial) - { - DBG1(DBG_KNL, " %H on %s", host, entry->ifname); - } - else + case RTM_DELLINK: { - DBG1(DBG_KNL, "%H appeared on %s", host, entry->ifname); + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (current->ifindex == msg->ifi_index) + { + /* we do not remove it, as an address may be added to a + * "down" interface and we wan't to know that. */ + current->flags = msg->ifi_flags; + break; + } + } + iterator->destroy(iterator); + break; } - - pthread_mutex_lock(&this->addrs_mutex); - this->addrs->insert_last(this->addrs, entry); - pthread_mutex_unlock(&this->addrs_mutex); } } - /** - * process a RTM_DELADDR from kernel + * process RTM_NEWADDR/RTM_DELADDR from kernel */ -static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *hdr) +static void process_addr(private_kernel_interface_t *this, + struct nlmsghdr *hdr, bool event) { struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr)); struct rtattr *rta = IFA_RTA(msg); size_t rtasize = IFA_PAYLOAD (hdr); host_t *host = NULL; + iterator_t *iterator; + interface_entry_t *entry; chunk_t local = chunk_empty, address = chunk_empty; - + while(RTA_OK(rta, rtasize)) { switch (rta->rta_type) @@ -619,7 +640,9 @@ static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *h rta = RTA_NEXT(rta, rtasize); } - /* same stuff as in newaddr */ + /* For PPP interfaces, we need the IFA_LOCAL address, + * IFA_ADDRESS is the peers address. But IFA_LOCAL is + * not included in all cases, so fallback to IFA_ADDRESS. */ if (local.ptr) { host = host_create_from_chunk(msg->ifa_family, local, 0); @@ -629,26 +652,66 @@ static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *h host = host_create_from_chunk(msg->ifa_family, address, 0); } - if (host) + if (host == NULL) + { /* bad family? */ + return; + } + + switch (hdr->nlmsg_type) { - address_entry_t *entry; - iterator_t *iterator; - - iterator = this->addrs->create_iterator_locked(this->addrs, - &this->addrs_mutex); - while (iterator->iterate(iterator, (void**)&entry)) + case RTM_NEWADDR: { - if (entry->ifindex == msg->ifa_index && - host->equals(host, entry->host)) + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); + while (iterator->iterate(iterator, (void**)&entry)) { - iterator->remove(iterator); - DBG1(DBG_KNL, "%H disappeared from %s", host, entry->ifname); - address_entry_destroy(entry); + if (entry->ifindex == msg->ifa_index) + { + entry->addresses->insert_last(entry->addresses, + host->clone(host)); + if (event) + { + DBG1(DBG_KNL, "%H appeared on %s", host, entry->ifname); + } + break; + } } + iterator->destroy(iterator); + break; } - iterator->destroy(iterator); - host->destroy(host); + case RTM_DELADDR: + { + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); + while (iterator->iterate(iterator, (void**)&entry)) + { + if (entry->ifindex == msg->ifa_index) + { + iterator_t *addresses; + host_t *current; + + addresses = entry->addresses->create_iterator( + entry->addresses, TRUE); + while (addresses->iterate(addresses, (void**)¤t)) + { + if (current->equals(current, host)) + { + addresses->remove(addresses); + current->destroy(current); + DBG1(DBG_KNL, "%H disappeared from %s", + host, entry->ifname); + } + } + addresses->destroy(addresses); + } + } + iterator->destroy(iterator); + break; + } + default: + break; } + host->destroy(host); } /** @@ -656,7 +719,7 @@ static void process_deladdr(private_kernel_interface_t *this, struct nlmsghdr *h */ static job_requeue_t receive_events(private_kernel_interface_t *this) { - char response[512]; + char response[1024]; struct nlmsghdr *hdr = (struct nlmsghdr*)response; struct sockaddr_nl addr; socklen_t addr_len = sizeof(addr); @@ -734,17 +797,18 @@ static job_requeue_t receive_events(private_kernel_interface_t *this) switch (hdr->nlmsg_type) { case RTM_NEWADDR: - process_newaddr(this, hdr, FALSE); - break; case RTM_DELADDR: - process_deladdr(this, hdr); + process_addr(this, hdr, TRUE); + break; + case RTM_NEWLINK: + case RTM_DELLINK: + process_link(this, hdr, TRUE); break; default: break; } } hdr = NLMSG_NEXT(hdr, len); - } return JOB_REQUEUE_DIRECT; } @@ -752,7 +816,8 @@ static job_requeue_t receive_events(private_kernel_interface_t *this) /** * send a netlink message and wait for a reply */ -static status_t netlink_send(int socket, struct nlmsghdr *in, +static status_t netlink_send(private_kernel_interface_t *this, + int socket, struct nlmsghdr *in, struct nlmsghdr **out, size_t *out_len) { int len, addr_len; @@ -760,13 +825,9 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, chunk_t result = chunk_empty, tmp; struct nlmsghdr *msg, peek; - static int seq = 200; - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - - - pthread_mutex_lock(&mutex); + pthread_mutex_lock(&this->mutex); - in->nlmsg_seq = ++seq; + in->nlmsg_seq = ++this->seq; in->nlmsg_pid = getpid(); memset(&addr, 0, sizeof(addr)); @@ -786,7 +847,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, /* interrupted, try again */ continue; } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno)); return FAILED; } @@ -818,23 +879,23 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, continue; } DBG1(DBG_IKE, "error reading from netlink socket: %s", strerror(errno)); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); return FAILED; } if (!NLMSG_OK(msg, len)) { DBG1(DBG_IKE, "received corrupted netlink message"); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); return FAILED; } - if (msg->nlmsg_seq != seq) + if (msg->nlmsg_seq != this->seq) { DBG1(DBG_IKE, "received invalid netlink sequence number"); - if (msg->nlmsg_seq < seq) + if (msg->nlmsg_seq < this->seq) { continue; } - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); return FAILED; } @@ -846,7 +907,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, len = recvfrom(socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); - if (len == sizeof(peek) && peek.nlmsg_seq == seq) + if (len == sizeof(peek) && peek.nlmsg_seq == this->seq) { /* seems to be multipart */ continue; @@ -857,7 +918,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, *out_len = result.len; *out = (struct nlmsghdr*)clalloc(result.ptr, result.len); - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&this->mutex); return SUCCESS; } @@ -865,12 +926,13 @@ static status_t netlink_send(int socket, struct nlmsghdr *in, /** * send a netlink message and wait for its acknowlegde */ -static status_t netlink_send_ack(int socket, struct nlmsghdr *in) +static status_t netlink_send_ack(private_kernel_interface_t *this, + int socket, struct nlmsghdr *in) { struct nlmsghdr *out, *hdr; size_t len; - if (netlink_send(socket, in, &out, &len) != SUCCESS) + if (netlink_send(this, socket, in, &out, &len) != SUCCESS) { return FAILED; } @@ -909,61 +971,116 @@ static status_t netlink_send_ack(int socket, struct nlmsghdr *in) /** * Initialize a list of local addresses. */ -static void init_address_list(private_kernel_interface_t *this) +static status_t init_address_list(private_kernel_interface_t *this) { char request[BUFFER_SIZE]; - struct nlmsghdr *out, *hdr; + struct nlmsghdr *out, *current, *in; struct rtgenmsg *msg; size_t len; + iterator_t *i_iface, *i_addr; + host_t *address; + interface_entry_t *entry; DBG1(DBG_IKE, "listening on interfaces:"); memset(&request, 0, sizeof(request)); - hdr = (struct nlmsghdr*)&request; - hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - hdr->nlmsg_type = RTM_GETADDR; - hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT; - msg = (struct rtgenmsg*)NLMSG_DATA(hdr); + in = (struct nlmsghdr*)&request; + in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + in->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT; + msg = (struct rtgenmsg*)NLMSG_DATA(in); msg->rtgen_family = AF_UNSPEC; - - if (netlink_send(this->socket_rt, hdr, &out, &len) == SUCCESS) + + /* get all links */ + in->nlmsg_type = RTM_GETLINK; + if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS) { - hdr = out; - while (NLMSG_OK(hdr, len)) + return FAILED; + } + current = out; + while (NLMSG_OK(current, len)) + { + switch (current->nlmsg_type) { - switch (hdr->nlmsg_type) - { - case RTM_NEWADDR: - { - process_newaddr(this, hdr, TRUE); - hdr = NLMSG_NEXT(hdr, len); - continue; - } - default: - hdr = NLMSG_NEXT(hdr, len); - continue; - case NLMSG_DONE: - break; - } - break; + case NLMSG_DONE: + break; + case RTM_NEWLINK: + process_link(this, current, FALSE); + /* fall through */ + default: + current = NLMSG_NEXT(current, len); + continue; } - free(out); + break; } - else + free(out); + + /* get all interface addresses */ + in->nlmsg_type = RTM_GETADDR; + if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS) { - DBG1(DBG_IKE, "unable to get local address list"); + return FAILED; } + current = out; + while (NLMSG_OK(current, len)) + { + switch (current->nlmsg_type) + { + case NLMSG_DONE: + break; + case RTM_NEWADDR: + process_addr(this, current, FALSE); + /* fall through */ + default: + current = NLMSG_NEXT(current, len); + continue; + } + break; + } + free(out); + + i_iface = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); + while (i_iface->iterate(i_iface, (void**)&entry)) + { + if (entry->flags & IFF_UP) + { + DBG1(DBG_KNL, " %s", entry->ifname); + i_addr = entry->addresses->create_iterator(entry->addresses, TRUE); + while (i_addr->iterate(i_addr, (void**)&address)) + { + DBG1(DBG_KNL, " %H", address); + } + i_addr->destroy(i_addr); + } + } + i_iface->destroy(i_iface); + + return SUCCESS; } /** * iterator hook to return address, not address_entry_t */ -bool address_iterator_hook(private_kernel_interface_t *this, - address_entry_t *in, host_t **out) +static hook_result_t hook(private_kernel_interface_t *this, + interface_entry_t *in, host_t **out) { - *out = in->host; - return TRUE; + if (!(in->flags & IFF_UP)) + { /* skip interfaces not up */ + return HOOK_SKIP; + } + + if (this->hiter == NULL) + { + this->hiter = in->addresses->create_iterator(in->addresses, TRUE); + } + while (this->hiter->iterate(this->hiter, (void**)out)) + { + return HOOK_AGAIN; + } + this->hiter->destroy(this->hiter); + this->hiter = NULL; + return HOOK_SKIP; } /** @@ -973,9 +1090,9 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this) { iterator_t *iterator; - iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); - iterator->set_iterator_hook(iterator, - (iterator_hook_t*)address_iterator_hook, this); + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); + iterator->set_iterator_hook(iterator, (iterator_hook_t*)hook, this); return iterator; } @@ -984,18 +1101,29 @@ static iterator_t *create_address_iterator(private_kernel_interface_t *this) */ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip) { - iterator_t *iterator; - address_entry_t *entry; + iterator_t *iterator, *addresses; + interface_entry_t *entry; + host_t *host; char *name = NULL; DBG2(DBG_IKE, "getting interface name for %H", ip); - iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); while (iterator->iterate(iterator, (void**)&entry)) { - if (ip->ip_equals(ip, entry->host)) + addresses = entry->addresses->create_iterator(entry->addresses, TRUE); + while (addresses->iterate(addresses, (void**)&host)) + { + if (ip->ip_equals(ip, host)) + { + name = strdup(entry->ifname); + break; + } + } + addresses->destroy(addresses); + if (name) { - name = strdup(entry->ifname); break; } } @@ -1019,8 +1147,8 @@ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip) static status_t get_address_by_ts(private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip) { - iterator_t *iterator; - address_entry_t *entry; + iterator_t *iterator, *addresses; + interface_entry_t *entry; host_t *host; int family; bool found = FALSE; @@ -1049,13 +1177,23 @@ static status_t get_address_by_ts(private_kernel_interface_t *this, } host->destroy(host); - iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); while (iterator->iterate(iterator, (void**)&entry)) { - if (ts->includes(ts, entry->host)) + addresses = entry->addresses->create_iterator(entry->addresses, TRUE); + while (addresses->iterate(addresses, (void**)&host)) + { + if (ts->includes(ts, host)) + { + found = TRUE; + *ip = host->clone(host); + break; + } + } + addresses->destroy(addresses); + if (found) { - found = TRUE; - *ip = entry->host->clone(entry->host); break; } } @@ -1075,23 +1213,34 @@ static status_t get_address_by_ts(private_kernel_interface_t *this, */ static int get_interface_index(private_kernel_interface_t *this, host_t* ip) { - iterator_t *iterator; - address_entry_t *entry; + iterator_t *iterator, *addresses; + interface_entry_t *entry; + host_t *host; int ifindex = 0; DBG2(DBG_IKE, "getting iface for %H", ip); - iterator = this->addrs->create_iterator_locked(this->addrs, &this->addrs_mutex); + iterator = this->interfaces->create_iterator_locked(this->interfaces, + &this->mutex); while (iterator->iterate(iterator, (void**)&entry)) { - if (ip->ip_equals(ip, entry->host)) + addresses = entry->addresses->create_iterator(entry->addresses, TRUE); + while (addresses->iterate(addresses, (void**)&host)) + { + if (ip->ip_equals(ip, host)) + { + ifindex = entry->ifindex; + break; + } + } + addresses->destroy(addresses); + if (ifindex) { - ifindex = entry->ifindex; break; } } iterator->destroy(iterator); - + if (ifindex == 0) { DBG1(DBG_IKE, "unable to get interface for %H", ip); @@ -1129,7 +1278,7 @@ static status_t manage_ipaddr(private_kernel_interface_t *this, int nlmsg_type, add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request)); - return netlink_send_ack(this->socket_rt, hdr); + return netlink_send_ack(this, this->socket_rt, hdr); } /** @@ -1190,7 +1339,7 @@ static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type chunk.len = sizeof(route->if_index); add_attribute(hdr, RTA_OIF, chunk, sizeof(request)); - return netlink_send_ack(this->socket_rt, hdr); + return netlink_send_ack(this, this->socket_rt, hdr); } @@ -1215,7 +1364,7 @@ static status_t add_ip(private_kernel_interface_t *this, } /* beware of deadlocks (e.g. send/receive packets while holding the lock) */ - iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex)); + iterator = this->vips->create_iterator_locked(this->vips, &this->mutex); while (iterator->iterate(iterator, (void**)&listed)) { if (listed->if_index == targetif && @@ -1269,7 +1418,7 @@ static status_t del_ip(private_kernel_interface_t *this, } /* beware of deadlocks (e.g. send/receive packets while holding the lock) */ - iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex)); + iterator = this->vips->create_iterator_locked(this->vips, &this->mutex); while (iterator->iterate(iterator, (void**)&listed)) { if (listed->if_index == targetif && @@ -1328,7 +1477,7 @@ static status_t get_spi(private_kernel_interface_t *this, userspi->min = 0xc0000000; userspi->max = 0xcFFFFFFF; - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1506,7 +1655,7 @@ static status_t add_sa(private_kernel_interface_t *this, rthdr = XFRM_RTA_NEXT(rthdr); } - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unalbe to add SAD entry with SPI 0x%x", spi); return FAILED; @@ -1544,7 +1693,7 @@ static status_t update_sa(private_kernel_interface_t *this, sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1613,7 +1762,7 @@ static status_t update_sa(private_kernel_interface_t *this, rtattr = RTA_NEXT(rtattr, rtsize); } } - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unalbe to update SAD entry with SPI 0x%x", spi); free(out); @@ -1655,7 +1804,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst, sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1721,7 +1870,7 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst, sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH; sa_id->family = dst->get_family(dst); - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unalbe to delete SAD entry with SPI 0x%x", spi); return FAILED; @@ -1755,7 +1904,7 @@ static status_t add_policy(private_kernel_interface_t *this, policy->direction = direction; /* find the policy, which matches EXACTLY */ - pthread_mutex_lock(&this->policies_mutex); + pthread_mutex_lock(&this->mutex); iterator = this->policies->create_iterator(this->policies, TRUE); while (iterator->iterate(iterator, (void**)¤t)) { @@ -1800,7 +1949,7 @@ static status_t add_policy(private_kernel_interface_t *this, policy_info->priority -= policy->sel.sport_mask ? 1 : 0; policy_info->action = XFRM_POLICY_ALLOW; policy_info->share = XFRM_SHARE_ANY; - pthread_mutex_unlock(&this->policies_mutex); + pthread_mutex_unlock(&this->mutex); /* policies don't expire */ policy_info->lft.soft_byte_limit = XFRM_INF; @@ -1834,7 +1983,7 @@ static status_t add_policy(private_kernel_interface_t *this, host2xfrm(src, &tmpl->saddr); host2xfrm(dst, &tmpl->id.daddr); - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unable to add policy %R===%R", src_ts, dst_ts); return FAILED; @@ -1904,7 +2053,7 @@ static status_t query_policy(private_kernel_interface_t *this, policy_id->sel = ts2selector(src_ts, dst_ts); policy_id->dir = direction; - if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS) + if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS) { hdr = out; while (NLMSG_OK(hdr, len)) @@ -1968,8 +2117,7 @@ static status_t del_policy(private_kernel_interface_t *this, policy.direction = direction; /* find the policy */ - pthread_mutex_lock(&this->policies_mutex); - iterator = this->policies->create_iterator(this->policies, TRUE); + iterator = this->policies->create_iterator_locked(this->policies, &this->mutex); while (iterator->iterate(iterator, (void**)¤t)) { if (memcmp(¤t->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 && @@ -1981,7 +2129,6 @@ static status_t del_policy(private_kernel_interface_t *this, /* is used by more SAs, keep in kernel */ DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed"); iterator->destroy(iterator); - pthread_mutex_unlock(&this->policies_mutex); return SUCCESS; } /* remove if last reference */ @@ -1990,7 +2137,6 @@ static status_t del_policy(private_kernel_interface_t *this, } } iterator->destroy(iterator); - pthread_mutex_unlock(&this->policies_mutex); if (!to_delete) { DBG1(DBG_KNL, "deleting policy %R===%R failed, not found", src_ts, dst_ts); @@ -2011,7 +2157,7 @@ static status_t del_policy(private_kernel_interface_t *this, route = to_delete->route; free(to_delete); - if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS) + if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS) { DBG1(DBG_KNL, "unable to delete policy %R===%R", src_ts, dst_ts); return FAILED; @@ -2041,7 +2187,7 @@ static void destroy(private_kernel_interface_t *this) close(this->socket_rt); this->vips->destroy(this->vips); this->policies->destroy(this->policies); - this->addrs->destroy_function(this->addrs, (void*)address_entry_destroy); + this->interfaces->destroy_function(this->interfaces, (void*)interface_entry_destroy); free(this); } @@ -2053,6 +2199,7 @@ kernel_interface_t *kernel_interface_create() private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t); struct sockaddr_nl addr; + /* public functions */ this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa; @@ -2072,10 +2219,10 @@ kernel_interface_t *kernel_interface_create() /* private members */ this->vips = linked_list_create(); this->policies = linked_list_create(); - this->addrs = linked_list_create(); - pthread_mutex_init(&this->policies_mutex,NULL); - pthread_mutex_init(&this->vips_mutex,NULL); - pthread_mutex_init(&this->addrs_mutex,NULL); + this->interfaces = linked_list_create(); + this->hiter = NULL; + this->seq = 200; + pthread_mutex_init(&this->mutex,NULL); memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; @@ -2092,13 +2239,13 @@ kernel_interface_t *kernel_interface_create() charon->kill(charon, "unable to bind RT netlink socket"); } - /* create and bind RT socket for events (address changes) */ + /* create and bind RT socket for events (address/interface changes) */ this->socket_rt_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (this->socket_rt_events <= 0) { charon->kill(charon, "unable to create RT event socket"); } - addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; + addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_LINK; if (bind(this->socket_rt_events, (struct sockaddr*)&addr, sizeof(addr))) { charon->kill(charon, "unable to bind RT event socket"); @@ -2132,7 +2279,10 @@ kernel_interface_t *kernel_interface_create() this, NULL, NULL); charon->processor->queue_job(charon->processor, (job_t*)this->job); - init_address_list(this); + if (init_address_list(this) != SUCCESS) + { + charon->kill(charon, "unable to get interface list"); + } return &this->public; } diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index a62ec5e3c..bc9094023 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -682,16 +682,16 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name, /** * Iterator hook for iterate, gets ike_sas instead of entries */ -static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in, - ike_sa_t **out) +static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in, + ike_sa_t **out) { /* check out entry */ if (wait_for_entry(this, in)) { *out = in->ike_sa; - return TRUE; + return HOOK_NEXT; } - return FALSE; + return HOOK_SKIP; } /** diff --git a/src/libstrongswan/utils/iterator.h b/src/libstrongswan/utils/iterator.h index 02a15c534..b4ff85bfb 100644 --- a/src/libstrongswan/utils/iterator.h +++ b/src/libstrongswan/utils/iterator.h @@ -26,15 +26,46 @@ #include <library.h> +typedef enum hook_result_t hook_result_t; + +/** + * @brief Return value of an iterator hook. + * + * Returning HOOK_AGAIN is useful to "inject" additional elements in an + * iteration, HOOK_NEXT is the normal iterator behavior, and HOOK_SKIP may + * be used to filter elements out. + * + * @ingroup utils + */ +enum hook_result_t { + + /** + * A value was placed in out, hook is called again with the same "in" + */ + HOOK_AGAIN, + + /** + * A value was placed in out, hook is called again with next "in" (if any) + */ + HOOK_NEXT, + + /** + * No value in out, call again with next "in" (if any) + */ + HOOK_SKIP, +}; + /** * @brief Iterator hook function prototype. * * @param param user supplied parameter * @param in the value the hook receives from the iterator * @param out the value supplied as a result to the iterator - * @return TRUE to return "out", FALSE to skip this value + * @return a hook_result_t + * + * @ingroup utils */ -typedef bool (iterator_hook_t)(void *param, void *in, void **out); +typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out); typedef struct iterator_t iterator_t; @@ -45,8 +76,6 @@ typedef struct iterator_t iterator_t; * iterator_t defines an interface for iterating over collections. * It allows searching, deleting, updating and inserting. * - * Thanks to JMP for iterator lessons :-) - * * @b Constructors: * - via linked_list_t.create_iterator, or * - any other class which supports the iterator_t interface @@ -84,8 +113,11 @@ struct iterator_t { * Sometimes it is useful to hook in an iterator. The hook function is * called before any successful return of iterate(). It takes the * iterator value, may manipulate it (or the references object), and returns - * the value that the iterate() function returns. + * the value that the iterate() function returns. Depending on the hook + * return value, the hook is called again, called with next, or skipped. * A value of NULL deactivates the iterator hook. + * If an iterator is hooked, only the iterate() method is valid, + * all other methods behave undefined. * * @param this calling object * @param hook iterator hook which manipulates the iterated value diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c index de043a02e..de52ea46a 100644 --- a/src/libstrongswan/utils/linked_list.c +++ b/src/libstrongswan/utils/linked_list.c @@ -151,10 +151,10 @@ static int get_list_count(private_iterator_t *this) /** * default iterator hook which does nothing */ -static bool iterator_hook(void *param, void *in, void **out) +static hook_result_t iterator_hook(void *param, void *in, void **out) { *out = in; - return TRUE; + return HOOK_NEXT; } /** @@ -180,40 +180,43 @@ static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook, */ static bool iterate(private_iterator_t *this, void** value) { - if (this->list->count == 0) - { - return FALSE; - } - if (this->current == NULL) + while (TRUE) { - this->current = (this->forward) ? this->list->first : this->list->last; - if (!this->hook(this->hook_param, this->current->value, value)) + if (this->forward) { - return iterate(this, value); + this->current = this->current ? this->current->next : this->list->first; } - return TRUE; - } - if (this->forward) - { - if (this->current->next == NULL) + else + { + this->current = this->current ? this->current->previous : this->list->last; + } + + if (this->current == NULL) { return FALSE; } - this->current = this->current->next; - if (!this->hook(this->hook_param, this->current->value, value)) + + switch (this->hook(this->hook_param, this->current->value, value)) { - return iterate(this, value); + case HOOK_AGAIN: + /* rewind */ + if (this->forward) + { + this->current = this->current->previous; + } + else + { + this->current = this->current->next; + } + break; + case HOOK_NEXT: + /* normal iteration */ + break; + case HOOK_SKIP: + /* advance */ + continue; } - return TRUE; - } - if (this->current->previous == NULL) - { - return FALSE; - } - this->current = this->current->previous; - if (!this->hook(this->hook_param, this->current->value, value)) - { - return iterate(this, value); + break; } return TRUE; } |