diff options
author | Martin Willi <martin@strongswan.org> | 2006-02-16 16:24:50 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2006-02-16 16:24:50 +0000 |
commit | 0a373aec33c977b061c57b72a3bc909ef5971b56 (patch) | |
tree | 99d9c1b185161f324a3393261bdfd5dcbad2938b /Source | |
parent | 30b5b412da849251d6000c2dc52731af3e5409b8 (diff) | |
download | strongswan-0a373aec33c977b061c57b72a3bc909ef5971b56.tar.bz2 strongswan-0a373aec33c977b061c57b72a3bc909ef5971b56.tar.xz |
- fixed socket code, so we know on which address we receive traffic
- AH/ESP setup in kernel is working now!!! :-)))
Diffstat (limited to 'Source')
-rw-r--r-- | Source/charon/config/configuration_manager.c | 10 | ||||
-rw-r--r-- | Source/charon/network/host.c | 23 | ||||
-rw-r--r-- | Source/charon/network/host.h | 19 | ||||
-rw-r--r-- | Source/charon/network/socket.c | 283 | ||||
-rw-r--r-- | Source/charon/utils/logger_manager.c | 1 |
5 files changed, 279 insertions, 57 deletions
diff --git a/Source/charon/config/configuration_manager.c b/Source/charon/config/configuration_manager.c index 07eaf53e2..9028a5c47 100644 --- a/Source/charon/config/configuration_manager.c +++ b/Source/charon/config/configuration_manager.c @@ -279,13 +279,14 @@ static void load_default_config (private_configuration_manager_t *this) sa_config_t *sa_config_a, *sa_config_b; traffic_selector_t *ts; - init_config_a = init_config_create("0.0.0.0","192.168.0.3",IKEV2_UDP_PORT,IKEV2_UDP_PORT); - init_config_b = init_config_create("0.0.0.0","192.168.0.2",IKEV2_UDP_PORT,IKEV2_UDP_PORT); + init_config_a = init_config_create("192.168.0.2","192.168.0.3",IKEV2_UDP_PORT,IKEV2_UDP_PORT); + init_config_b = init_config_create("192.168.0.3","192.168.0.2",IKEV2_UDP_PORT,IKEV2_UDP_PORT); /* IKE proposals for alice */ proposal = proposal_create(1); proposal->add_algorithm(proposal, IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); + proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); proposal->add_algorithm(proposal, IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0); proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); @@ -294,7 +295,8 @@ static void load_default_config (private_configuration_manager_t *this) /* IKE proposals for bob */ proposal = proposal_create(1); proposal->add_algorithm(proposal, IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); + proposal->add_algorithm(proposal, IKE, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); + proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); proposal->add_algorithm(proposal, IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0); proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); init_config_b->add_proposal(init_config_b, proposal); @@ -346,7 +348,7 @@ static void load_default_config (private_configuration_manager_t *this) // proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); + proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); diff --git a/Source/charon/network/host.c b/Source/charon/network/host.c index a8fab245d..7d120886e 100644 --- a/Source/charon/network/host.c +++ b/Source/charon/network/host.c @@ -319,3 +319,26 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) allocator_free(this); return NULL; } + +/* + * Described in header. + */ +host_t *host_create_from_sockaddr(sockaddr_t *sockaddr) +{ + chunk_t address; + + switch (sockaddr->sa_family) + { + /* IPv4 */ + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)sockaddr; + address.ptr = (void*)&(sin->sin_addr.s_addr); + address.len = 4; + return host_create_from_chunk(AF_INET, address, ntohs(sin->sin_port)); + } + default: + return NULL; + } +} + diff --git a/Source/charon/network/host.h b/Source/charon/network/host.h index 3cf0c6397..c5293bcdf 100644 --- a/Source/charon/network/host.h +++ b/Source/charon/network/host.h @@ -45,6 +45,7 @@ typedef struct host_t host_t; * @b Constructors: * - host_create() * - host_create_from_chunk() + * - host_create_from_sockaddr() * * @todo Add IPv6 support * @@ -166,7 +167,7 @@ struct host_t { }; /** - * @brief Constructor to create a host_t object + * @brief Constructor to create a host_t object from an address string * * Currently supports only IPv4! * @@ -182,7 +183,7 @@ struct host_t { host_t *host_create(int family, char *address, u_int16_t port); /** - * @brief Constructor to create a host_t object + * @brief Constructor to create a host_t object from an address chunk * * Currently supports only IPv4! * @@ -197,5 +198,19 @@ host_t *host_create(int family, char *address, u_int16_t port); */ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); +/** + * @brief Constructor to create a host_t object from a sockaddr struct + * + * Currently supports only IPv4! + * + * @param sockaddr sockaddr struct which contains family, address and port + * @return + * - host_t object + * - NULL, if family not supported. + * + * @ingroup network + */ +host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); + #endif /*HOST_H_*/ diff --git a/Source/charon/network/socket.c b/Source/charon/network/socket.c index d26f66a9b..d02e21476 100644 --- a/Source/charon/network/socket.c +++ b/Source/charon/network/socket.c @@ -8,6 +8,10 @@ /* * Copyright (C) 2005 Jan Hutter, Martin Willi * Hochschule fuer Technik Rapperswil + * Copyright (C) 1998-2002 D. Hugh Redelmeier. + * Copyright (C) 1997 Angelos D. Keromytis. + * + * Some parts of interface lookup code from pluto. * * 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 @@ -27,6 +31,9 @@ #include <errno.h> #include <unistd.h> #include <stdlib.h> +#include <fcntl.h> +#include <net/if.h> +#include <sys/ioctl.h> #include "socket.h" @@ -35,6 +42,24 @@ #include <utils/logger_manager.h> +typedef struct interface_t interface_t; + +/** + * An interface on which we listen. + */ +struct interface_t { + + /** + * Name of the interface + */ + char name[IFNAMSIZ+1]; + + /** + * Associated socket + */ + int socket_fd; +}; + typedef struct private_socket_t private_socket_t; /** @@ -45,11 +70,16 @@ struct private_socket_t{ * public functions */ socket_t public; - + /** - * currently we only have one socket, maybe more in the future ? + * Master socket */ - int socket_fd; + int master_fd; + + /** + * List of all socket to listen + */ + linked_list_t* interfaces; /** * logger for this socket @@ -64,35 +94,75 @@ status_t receiver(private_socket_t *this, packet_t **packet) { char buffer[MAX_PACKET]; chunk_t data; - int oldstate; - host_t *source, *dest; packet_t *pkt = packet_create(); - - /* add packet destroy handler for cancellation, enable cancellation */ - pthread_cleanup_push((void(*)(void*))pkt->destroy, (void*)pkt); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + host_t *source, *dest; + int bytes_read = 0; source = host_create(AF_INET, "0.0.0.0", 0); dest = host_create(AF_INET, "0.0.0.0", 0); pkt->set_source(pkt, source); pkt->set_destination(pkt, dest); - - this->logger->log(this->logger, CONTROL|LEVEL1, "going to read from socket"); - /* do the read */ - data.len = recvfrom(this->socket_fd, buffer, MAX_PACKET, 0, - source->get_sockaddr(source), - source->get_sockaddr_len(source)); - - /* reset cancellation, remove packet destroy handler (without executing) */ - pthread_setcancelstate(oldstate, NULL); - pthread_cleanup_pop(0); - - - if (data.len < 0) + + while (bytes_read >= 0) { - pkt->destroy(pkt); - this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno)); - return FAILED; + int max_fd = 1; + fd_set readfds; + iterator_t *iterator; + int oldstate; + interface_t *interface; + + /* build fd_set */ + FD_ZERO(&readfds); + iterator = this->interfaces->create_iterator(this->interfaces, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)&interface); + FD_SET(interface->socket_fd, &readfds); + if (interface->socket_fd > max_fd) + { + max_fd = interface->socket_fd + 1; + } + } + iterator->destroy(iterator); + + /* add packet destroy handler for cancellation, enable cancellation */ + pthread_cleanup_push((void(*)(void*))pkt->destroy, (void*)pkt); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + + this->logger->log(this->logger, CONTROL|LEVEL1, "waiting on sockets"); + bytes_read = select(max_fd, &readfds, NULL, NULL, NULL); + + /* reset cancellation, remove packet destroy handler (without executing) */ + pthread_setcancelstate(oldstate, NULL); + pthread_cleanup_pop(0); + + if (bytes_read < 0) + { + this->logger->log(this->logger, ERROR, "error reading from socket: %s", strerror(errno)); + continue; + } + + /* read on the first nonblocking socket */ + bytes_read = 0; + iterator = this->interfaces->create_iterator(this->interfaces, TRUE); + while (iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)&interface); + if (FD_ISSET(interface->socket_fd, &readfds)) + { + /* do the read */ + bytes_read = recvfrom(interface->socket_fd, buffer, MAX_PACKET, 0, + source->get_sockaddr(source), + source->get_sockaddr_len(source)); + getsockname(interface->socket_fd, dest->get_sockaddr(dest), dest->get_sockaddr_len(dest)); + break; + } + } + iterator->destroy(iterator); + if (bytes_read > 0) + { + break; + } } this->logger->log(this->logger, CONTROL, "received packet from %s:%d", @@ -100,9 +170,9 @@ status_t receiver(private_socket_t *this, packet_t **packet) source->get_port(source)); /* fill in packet */ + data.len = bytes_read; data.ptr = allocator_alloc(data.len); memcpy(data.ptr, buffer, data.len); - pkt->set_data(pkt, data); /* return packet */ @@ -124,12 +194,13 @@ status_t sender(private_socket_t *this, packet_t *packet) dest = packet->get_destination(packet); data = packet->get_data(packet); - this->logger->log(this->logger, CONTROL, "sending packet to %s:%d", - dest->get_address(dest), + dest->get_address(dest), dest->get_port(dest)); + /* send data */ - bytes_sent = sendto(this->socket_fd, data.ptr, data.len, 0, + /* TODO: should we send via the interface we received the packet? */ + bytes_sent = sendto(this->master_fd, data.ptr, data.len, 0, dest->get_sockaddr(dest), *(dest->get_sockaddr_len(dest))); if (bytes_sent != data.len) @@ -141,48 +212,158 @@ status_t sender(private_socket_t *this, packet_t *packet) } /** + * Find all suitable interfaces, bind them and add them to the list + */ +static status_t build_interface_list(private_socket_t *this, u_int16_t port) +{ + int on = TRUE; + int i; + struct sockaddr_in addr; + struct ifconf ifconf; + struct ifreq buf[300]; + + /* master socket for querying socket for a specific interfaces */ + this->master_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (this->master_fd == -1) + { + this->logger->log(this->logger, ERROR, "could not open IPv4 master socket!"); + return FAILED; + } + + /* allow binding of multiplo sockets */ + if (setsockopt(this->master_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) + { + this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on master socket!"); + return FAILED; + } + + /* bind the master socket */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + if (bind(this->master_fd,(struct sockaddr*)&addr, sizeof(addr)) < 0) + { + this->logger->log(this->logger, ERROR, "unable to bind master socket!"); + return FAILED; + } + + /* get all interfaces */ + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf = (void*) buf; + memset(buf, 0, sizeof(buf)); + if (ioctl(this->master_fd, SIOCGIFCONF, &ifconf) == -1) + { + this->logger->log(this->logger, ERROR, "unable to get interfaces!"); + return FAILED; + } + + /* add every interesting interfaces to our interface list */ + for (i = 0; (i+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; i++) + { + struct sockaddr_in *current = (struct sockaddr_in*) &buf[i].ifr_addr; + struct ifreq auxinfo; + int skt; + interface_t *interface; + + if (current->sin_family != AF_INET) + { + /* ignore all but AF_INET interfaces */ + continue; + } + + /* get auxilary info about socket */ + memset(&auxinfo, 0, sizeof(auxinfo)); + memcpy(auxinfo.ifr_name, buf[i].ifr_name, IFNAMSIZ); + if (ioctl(this->master_fd, SIOCGIFFLAGS, &auxinfo) == -1) + { + this->logger->log(this->logger, ERROR, "unable to SIOCGIFFLAGS master socket!"); + continue; + } + if (!(auxinfo.ifr_flags & IFF_UP)) + { + /* ignore an interface that isn't up */ + continue; + } + if (current->sin_addr.s_addr == 0) + { + /* ignore unconfigured interfaces */ + continue; + } + + /* set up interface socket */ + skt = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (socket < 0) + { + this->logger->log(this->logger, ERROR, "unable to open interface socket!"); + continue; + } + if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) + { + this->logger->log(this->logger, ERROR, "unable to set SO_REUSEADDR on interface socket!"); + close(skt); + continue; + } + current->sin_port = htons(port); + current->sin_family = AF_INET; + if (bind(skt, (struct sockaddr*)current, sizeof(struct sockaddr_in)) < 0) + { + this->logger->log(this->logger, ERROR, "unable to bind interface socket!"); + close(skt); + continue; + } + + /* add socket with interface name to list */ + interface = allocator_alloc_thing(interface_t); + memcpy(interface->name, buf[i].ifr_name, IFNAMSIZ); + interface->name[IFNAMSIZ] = '\0'; + interface->socket_fd = skt; + this->interfaces->insert_last(this->interfaces, (void*)interface); + } + + if (this->interfaces->get_count(this->interfaces) == 0) + { + this->logger->log(this->logger, ERROR, "unable to find any usable interface!"); + return FAILED; + } + return SUCCESS; +} + +/** * implementation of socket_t.destroy */ void destroy(private_socket_t *this) { - close(this->socket_fd); + interface_t *interface; + while (this->interfaces->remove_last(this->interfaces, (void**)&interface) == SUCCESS) + { + close(interface->socket_fd); + allocator_free(interface); + } + this->interfaces->destroy(this->interfaces); charon->logger_manager->destroy_logger(charon->logger_manager, this->logger); + close(this->master_fd); allocator_free(this); } +/* + * See header for description + */ socket_t *socket_create(u_int16_t port) { private_socket_t *this = allocator_alloc_thing(private_socket_t); - struct sockaddr_in addr; /* public functions */ this->public.send = (status_t(*)(socket_t*, packet_t*))sender; this->public.receive = (status_t(*)(socket_t*, packet_t**))receiver; - this->public.destroy = (void(*)(socket_t*))destroy; + this->public.destroy = (void(*)(socket_t*)) destroy; this->logger = charon->logger_manager->create_logger(charon->logger_manager, SOCKET, NULL); + this->interfaces = linked_list_create(); - /* create default ipv4 socket */ - this->socket_fd = socket(PF_INET, SOCK_DGRAM, 0); - if (this->socket_fd < 0) + if (build_interface_list(this, port) != SUCCESS) { - this->logger->log(this->logger, ERROR, "unable to open socket: %s", strerror(errno)); - charon->logger_manager->destroy_logger(charon->logger_manager, this->logger); - allocator_free(this); - charon->kill(charon, "socket could not be opened"); + charon->kill(charon, "could not bind any interface!"); } - /* bind socket to all interfaces */ - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(port); - if (bind(this->socket_fd,(struct sockaddr*)&addr, sizeof(addr)) < 0) - { - this->logger->log(this->logger, ERROR, "unable to bind socket to port %d: %s", port, strerror(errno)); - charon->logger_manager->destroy_logger(charon->logger_manager, this->logger); - allocator_free(this); - charon->kill(charon, "socket could not be opened"); - } - return (socket_t*)this; } diff --git a/Source/charon/utils/logger_manager.c b/Source/charon/utils/logger_manager.c index fb832efdf..1a2da19bc 100644 --- a/Source/charon/utils/logger_manager.c +++ b/Source/charon/utils/logger_manager.c @@ -209,6 +209,7 @@ static logger_t *create_logger(private_logger_manager_t *this, logger_context_t case RECEIVER: break; case SOCKET: + logger_level |= FULL; break; case DAEMON: break; |