X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=http_send.c;h=7fe216b1a226987300dbd8aea89441a6da1da98a;hb=1cb120bccde2afb0d36be7b7b1b004bf2ec2e5dd;hp=8cce85a15c079599f16ea5e800082cbe0db2b215;hpb=24e2b57dde50a6fe33deee034d34181eece09834;p=paraslash.git diff --git a/http_send.c b/http_send.c index 8cce85a1..7fe216b1 100644 --- a/http_send.c +++ b/http_send.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Andre Noll + * Copyright (C) 2005-2008 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -25,8 +25,9 @@ #include "fd.h" #include "chunk_queue.h" +/** Message sent to clients that do not send a valid get request. */ #define HTTP_ERR_MSG "HTTP/1.0 400 Bad Request\n" -/** \endcond */ + /** The possible states of a client from the server's POV. */ enum http_status { @@ -49,7 +50,7 @@ enum http_status { /** The list of connected clients. */ static struct list_head clients; /** The whitelist/blacklist. */ -static struct list_head access_perm_list; +static struct list_head http_acl; /** Describes one client that connected the tcp port of the http sender. */ struct http_client { @@ -77,7 +78,7 @@ struct access_info { struct in_addr addr; /** The netmask for this entry. */ unsigned netmask; - /** The position of this entry in the access_perm_list. */ + /** The position of this entry in the acl. */ struct list_head node; }; @@ -201,24 +202,37 @@ static void http_send( long unsigned current_chunk, } } +/** + * Return true if addr_1 matches addr_2 in the first `netmask' bits. + */ +static int v4_addr_match(uint32_t addr_1, uint32_t addr_2, uint8_t netmask) +{ + uint32_t mask = ~0U; + + if (netmask < 32) + mask <<= (32 - netmask); + return (htonl(addr_1) & mask) == (htonl(addr_2) & mask); +} + static int host_in_access_perm_list(struct http_client *hc) { - struct sockaddr_storage ss; - socklen_t sslen = sizeof(ss); + struct access_info *ai, *tmp; + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + struct in_addr v4_addr; if (getpeername(hc->fd, (struct sockaddr *)&ss, &sslen) < 0) { - PARA_ERROR_LOG("can not determine address family: %s\n", strerror(errno)); - } else if (ss.ss_family == AF_INET) { - /* FIXME: access restriction is (currently) only supported for IPv4 */ - struct access_info *ai, *tmp; - struct in_addr client_addr = ((struct sockaddr_in *)&ss)->sin_addr; - - list_for_each_entry_safe(ai, tmp, &access_perm_list, node) { - unsigned mask = ((~0U) >> ai->netmask); - if ((client_addr.s_addr & mask) == (ai->addr.s_addr & mask)) - return 1; - } + PARA_ERROR_LOG("Can not determine peer address: %s\n", strerror(errno)); + goto no_match; } + v4_addr = extract_v4_addr(&ss); + if (!v4_addr.s_addr) + goto no_match; + + list_for_each_entry_safe(ai, tmp, &http_acl, node) + if (v4_addr_match(v4_addr.s_addr, ai->addr.s_addr, ai->netmask)) + return 1; +no_match: return 0; } @@ -350,7 +364,7 @@ static int open_tcp_port(int port) } ret = mark_fd_nonblocking(server_fd); if (ret < 0) { - PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret)); + PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); } self->status = SENDER_ON; @@ -381,7 +395,7 @@ static void del_perm_list_entry(struct sender_command_data *scd) { struct access_info *ai, *tmp; - list_for_each_entry_safe(ai, tmp, &access_perm_list, node) { + list_for_each_entry_safe(ai, tmp, &http_acl, node) { char *nad = para_strdup(inet_ntoa(ai->addr)); if (!strcmp(nad, inet_ntoa(scd->addr)) && ai->netmask == scd->netmask) { @@ -401,7 +415,7 @@ static void add_perm_list_entry(struct sender_command_data *scd) ai->netmask = scd->netmask; PARA_INFO_LOG("adding %s/%i to access list\n", inet_ntoa(ai->addr), ai->netmask); - para_list_add(&ai->node, &access_perm_list); + para_list_add(&ai->node, &http_acl); } static int http_com_deny(struct sender_command_data *scd) @@ -428,7 +442,7 @@ static char *http_info(void) struct access_info *ai, *tmp_ai; struct http_client *hc, *tmp_hc; - list_for_each_entry_safe(ai, tmp_ai, &access_perm_list, node) { + list_for_each_entry_safe(ai, tmp_ai, &http_acl, node) { char *tmp = make_message("%s%s/%d ", ap? ap : "", inet_ntoa(ai->addr), ai->netmask); free(ap); @@ -460,14 +474,14 @@ static char *http_info(void) return ret; } -static void init_access_control_list(void) +static void init_acl(struct list_head *acl, char * const *acl_info, int num) { int i; struct sender_command_data scd; - INIT_LIST_HEAD(&access_perm_list); - for (i = 0; i < conf.http_access_given; i++) { - char *arg = para_strdup(conf.http_access_arg[i]); + INIT_LIST_HEAD(acl); + for (i = 0; i < num; i++) { + char *arg = para_strdup(acl_info[i]); char *p = strchr(arg, '/'); if (!p) goto err; @@ -521,7 +535,7 @@ void http_send_init(struct sender *s) s->client_cmds[SENDER_ADD] = NULL; s->client_cmds[SENDER_DELETE] = NULL; self = s; - init_access_control_list(); + init_acl(&http_acl, conf.http_access_arg, conf.http_access_given); if (!conf.http_no_autostart_given) open_tcp_port(conf.http_port_arg); /* ignore errors */ PARA_DEBUG_LOG("%s", "http sender init complete\n");