X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=http_send.c;h=7fe216b1a226987300dbd8aea89441a6da1da98a;hp=799c06cc2dfa2b4400882cdb14fb16089d1bc77e;hb=1cb120bccde2afb0d36be7b7b1b004bf2ec2e5dd;hpb=7a0852896a75d852dbd2ac848ec5c0be3b5dea71 diff --git a/http_send.c b/http_send.c index 799c06cc..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; }; @@ -87,8 +88,8 @@ static struct sender *self; static void http_shutdown_client(struct http_client *hc, const char *msg) { - PARA_INFO_LOG("shutting down %s on fd %d (%s)\n", - hc->name, hc->fd, msg); + PARA_INFO_LOG("shutting down %s on fd %d (%s)\n", hc->name, hc->fd, + msg); numclients--; free(hc->name); close(hc->fd); @@ -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; } @@ -291,14 +305,14 @@ static void http_post_select(fd_set *rfds, fd_set *wfds) hc->cq = cq_new(MAX_BACKLOG); numclients++; PARA_INFO_LOG("accepted client #%d: %s (fd %d)\n", numclients, - hc->name, hc->fd); + hc->name, hc->fd); para_list_add(&hc->node, &clients); add_close_on_fork_list(hc->fd); mark_fd_nonblocking(hc->fd); return; err_out: PARA_WARNING_LOG("ignoring connect request from %s (%s)\n", - hc->name, err_msg); + hc->name, err_msg); if (hc->fd > 0) close(hc->fd); free(hc); @@ -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,15 +442,14 @@ 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); ap = tmp; } list_for_each_entry_safe(hc, tmp_hc, &clients, node) { - char *tmp = make_message("%s%s ", clnts? clnts : "", - hc->name); + char *tmp = make_message("%s%s ", clnts? clnts : "", hc->name); free(clnts); clnts = tmp; } @@ -461,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; @@ -522,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");