From 71b09488a170514f538261aad904718ee37831b1 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 00:58:12 +0100 Subject: [PATCH 1/8] .c files are not executable --- src/capmt.c | 0 src/dvr/dvr_rec.c | 0 src/streaming.c | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/capmt.c mode change 100755 => 100644 src/dvr/dvr_rec.c mode change 100755 => 100644 src/streaming.c diff --git a/src/capmt.c b/src/capmt.c old mode 100755 new mode 100644 diff --git a/src/dvr/dvr_rec.c b/src/dvr/dvr_rec.c old mode 100755 new mode 100644 diff --git a/src/streaming.c b/src/streaming.c old mode 100755 new mode 100644 From 294b8d92c2d3a9bdd115788b8293b785cfd3f5af Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 02:18:13 +0100 Subject: [PATCH 2/8] Make tcp_server_create IPv6 aware --- src/tcp.c | 53 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/tcp.c b/src/tcp.c index a97b079b..ab3d432f 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -478,21 +478,55 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque) int fd, x; struct epoll_event e; tcp_server_t *ts; - struct sockaddr_in s; + struct addrinfo hints, *res, *ressave, *use = NULL; + char *portBuf = (char*)malloc(6); int one = 1; + int zero = 0; + memset(&e, 0, sizeof(e)); - fd = tvh_socket(AF_INET, SOCK_STREAM, 0); + + snprintf(portBuf, 6, "%d", port); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + x = getaddrinfo(NULL, portBuf, &hints, &res); + free(portBuf); + + if(x != 0) + return NULL; + + ressave = res; + while(res) + { + if(res->ai_family == AF_INET6) + { + use = res; + break; + } + else if(use == NULL) + { + use = res; + } + res = res->ai_next; + } + + fd = tvh_socket(use->ai_family, use->ai_socktype, use->ai_protocol); if(fd == -1) return NULL; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); + if(use->ai_family == AF_INET6) + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(int)); - memset(&s, 0, sizeof(s)); - s.sin_family = AF_INET; - s.sin_port = htons(port); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); - x = bind(fd, (struct sockaddr *)&s, sizeof(s)); - if(x < 0) { + x = bind(fd, use->ai_addr, use->ai_addrlen); + freeaddrinfo(ressave); + + if(x != 0) + { close(fd); return NULL; } @@ -504,11 +538,10 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque) ts->start = start; ts->opaque = opaque; - e.events = EPOLLIN; e.data.ptr = ts; - epoll_ctl(tcp_server_epoll_fd, EPOLL_CTL_ADD, fd, &e); + return ts; } From abd5487cc7e6256345be19f1b10e77e1271f9915 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 02:41:16 +0100 Subject: [PATCH 3/8] Make tcp code use sockaddr_storage instead of sockaddr_in --- src/tcp.c | 8 ++++---- src/tcp.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tcp.c b/src/tcp.c index ab3d432f..84313663 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -359,8 +359,8 @@ typedef struct tcp_server_launch_t { tcp_server_callback_t *start; void *opaque; int fd; - struct sockaddr_in peer; - struct sockaddr_in self; + struct sockaddr_storage peer; + struct sockaddr_storage self; } tcp_server_launch_t; @@ -443,7 +443,7 @@ tcp_server_loop(void *aux) tsl = malloc(sizeof(tcp_server_launch_t)); tsl->start = ts->start; tsl->opaque = ts->opaque; - slen = sizeof(struct sockaddr_in); + slen = sizeof(struct sockaddr_storage); tsl->fd = accept(ts->serverfd, (struct sockaddr *)&tsl->peer, &slen); @@ -455,7 +455,7 @@ tcp_server_loop(void *aux) } - slen = sizeof(struct sockaddr_in); + slen = sizeof(struct sockaddr_storage); if(getsockname(tsl->fd, (struct sockaddr *)&tsl->self, &slen)) { close(tsl->fd); free(tsl); diff --git a/src/tcp.h b/src/tcp.h index e9d9534c..b7a7c876 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -27,8 +27,8 @@ int tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout); typedef void (tcp_server_callback_t)(int fd, void *opaque, - struct sockaddr_in *peer, - struct sockaddr_in *self); + struct sockaddr_storage *peer, + struct sockaddr_storage *self); void *tcp_server_create(int port, tcp_server_callback_t *start, void *opaque); From b08a3c40d7829f3671fdddfc1840bd16960891c6 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 03:05:21 +0100 Subject: [PATCH 4/8] Make http server IPv6 ready --- src/http.c | 24 ++++++++++++++---------- src/http.h | 4 ++-- src/tcp.c | 25 +++++++++++++++++++++++++ src/tcp.h | 2 ++ 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/http.c b/src/http.c index 610e72e3..c668a02f 100644 --- a/src/http.c +++ b/src/http.c @@ -247,9 +247,12 @@ void http_error(http_connection_t *hc, int error) { const char *errtxt = http_rc2str(error); + char *addrstr = (char*)malloc(50); + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50); tvhlog(LOG_ERR, "HTTP", "%s: %s -- %d", - inet_ntoa(hc->hc_peer->sin_addr), hc->hc_url, error); + addrstr, hc->hc_url, error); + free(addrstr); htsbuf_queue_flush(&hc->hc_reply); @@ -315,10 +318,13 @@ http_access_verify(http_connection_t *hc, int mask) { const char *ticket_id = http_arg_get(&hc->hc_req_args, "ticket"); - if(!access_ticket_verify(ticket_id, hc->hc_url)) { + if(!access_ticket_verify(ticket_id, hc->hc_url)) + { + char *addrstr = (char*)malloc(50); + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50); tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s", - inet_ntoa(hc->hc_peer->sin_addr), ticket_id, - hc->hc_url); + addrstr, ticket_id, hc->hc_url); + free(addrstr); return 0; } @@ -504,11 +510,9 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill) if(hc->hc_username != NULL) { hc->hc_representative = strdup(hc->hc_username); } else { - hc->hc_representative = malloc(30); + hc->hc_representative = malloc(50); /* Not threadsafe ? */ - snprintf(hc->hc_representative, 30, - "%s", inet_ntoa(hc->hc_peer->sin_addr)); - + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, hc->hc_representative, 50); } switch(hc->hc_version) { @@ -777,8 +781,8 @@ http_serve_requests(http_connection_t *hc, htsbuf_queue_t *spill) * */ static void -http_serve(int fd, void *opaque, struct sockaddr_in *peer, - struct sockaddr_in *self) +http_serve(int fd, void *opaque, struct sockaddr_storage *peer, + struct sockaddr_storage *self) { htsbuf_queue_t spill; http_connection_t hc; diff --git a/src/http.h b/src/http.h index 2a29b8a9..9e3d061c 100644 --- a/src/http.h +++ b/src/http.h @@ -39,8 +39,8 @@ typedef struct http_arg { typedef struct http_connection { int hc_fd; - struct sockaddr_in *hc_peer; - struct sockaddr_in *hc_self; + struct sockaddr_storage *hc_peer; + struct sockaddr_storage *hc_self; char *hc_representative; char *hc_url; diff --git a/src/tcp.c b/src/tcp.c index 84313663..3653e8b2 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -344,6 +344,31 @@ tcp_read_timeout(int fd, void *buf, size_t len, int timeout) } +/** + * + */ +char * +tcp_get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) +{ + if(sa == NULL || s == NULL) + return NULL; + + switch(sa->sa_family) + { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in*)sa)->sin_addr), s, maxlen); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6*)sa)->sin6_addr), s, maxlen); + break; + default: + strncpy(s, "Unknown AF", maxlen); + return NULL; + } + + return s; +} + /** * */ diff --git a/src/tcp.h b/src/tcp.h index b7a7c876..187a9d57 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -44,4 +44,6 @@ int tcp_write_queue(int fd, htsbuf_queue_t *q); int tcp_read_timeout(int fd, void *buf, size_t len, int timeout); +char *tcp_get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen); + #endif /* TCP_H_ */ From 0a4f32bfba5defb663363ab8e101891eb7a86aac Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 03:25:21 +0100 Subject: [PATCH 5/8] Make htsp_server and webui IPv6 ready --- src/htsp_server.c | 21 ++++++++++++--------- src/webui/comet.c | 15 ++++++++++++--- src/webui/webui.c | 13 ++++++++++--- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/htsp_server.c b/src/htsp_server.c index 75b15d41..e3f289ab 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -115,7 +115,7 @@ typedef struct htsp_connection { LIST_ENTRY(htsp_connection) htsp_link; int htsp_fd; - struct sockaddr_in *htsp_peer; + struct sockaddr_storage *htsp_peer; uint32_t htsp_version; @@ -464,19 +464,22 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp) htsmsg_add_str(out, "channelName", ch->ch_name); if(ch->ch_icon != NULL) { uint32_t id; - struct sockaddr_in addr; + struct sockaddr_storage addr; socklen_t addrlen; if ((id = imagecache_get_id(ch->ch_icon))) { size_t p = 0; char url[256]; + char buf[50]; if (htsp->htsp_version < 8) { addrlen = sizeof(addr); getsockname(htsp->htsp_fd, (struct sockaddr*)&addr, &addrlen); + tcp_get_ip_str((struct sockaddr*)&addr, buf, 50); strcpy(url, "http://"); p = strlen(url); - inet_ntop(AF_INET, &addr.sin_addr, url+p, sizeof(url)-p); - p = strlen(url); - p += snprintf(url+p, sizeof(url)-p, ":%hd%s", + p += snprintf(url+p, sizeof(url)-p, "%s%s%s:%hd%s", + (addr.ss_family == AF_INET6)?"[":"", + buf, + (addr.ss_family == AF_INET6)?"]":"", tvheadend_webui_port, tvheadend_webroot ?: ""); } @@ -1871,14 +1874,14 @@ htsp_write_scheduler(void *aux) * */ static void -htsp_serve(int fd, void *opaque, struct sockaddr_in *source, - struct sockaddr_in *self) +htsp_serve(int fd, void *opaque, struct sockaddr_storage *source, + struct sockaddr_storage *self) { htsp_connection_t htsp; - char buf[30]; + char buf[50]; htsp_subscription_t *s; - snprintf(buf, sizeof(buf), "%s", inet_ntoa(source->sin_addr)); + tcp_get_ip_str((struct sockaddr*)source, buf, 50); memset(&htsp, 0, sizeof(htsp_connection_t)); diff --git a/src/webui/comet.c b/src/webui/comet.c index a540dbf6..aaf42ae0 100644 --- a/src/webui/comet.c +++ b/src/webui/comet.c @@ -32,6 +32,7 @@ #include "http.h" #include "webui/webui.h" #include "access.h" +#include "tcp.h" static pthread_mutex_t comet_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t comet_cond = PTHREAD_COND_INITIALIZER; @@ -153,16 +154,24 @@ comet_access_update(http_connection_t *hc, comet_mailbox_t *cmb) static void comet_serverIpPort(http_connection_t *hc, comet_mailbox_t *cmb) { - char buf[INET_ADDRSTRLEN + 1]; + char buf[50]; + uint32_t port; - inet_ntop(AF_INET, &hc->hc_self->sin_addr, buf, sizeof(buf)); + tcp_get_ip_str((struct sockaddr*)hc->hc_self, buf, 50); + + if(hc->hc_self->ss_family == AF_INET) + port = ((struct sockaddr_in*)hc->hc_self)->sin_port; + else if(hc->hc_self->ss_family == AF_INET6) + port = ((struct sockaddr_in6*)hc->hc_self)->sin6_port; + else + port = 0; htsmsg_t *m = htsmsg_create_map(); htsmsg_add_str(m, "notificationClass", "setServerIpPort"); htsmsg_add_str(m, "ip", buf); - htsmsg_add_u32(m, "port", ntohs(hc->hc_self->sin_port)); + htsmsg_add_u32(m, "port", ntohs(port)); if(cmb->cmb_messages == NULL) cmb->cmb_messages = htsmsg_create_list(); diff --git a/src/webui/webui.c b/src/webui/webui.c index 3e1e525c..a7262115 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -45,6 +45,7 @@ #include "dvb/dvb.h" #include "dvb/dvb_support.h" #include "imagecache.h" +#include "tcp.h" /** * @@ -563,6 +564,7 @@ http_stream_service(http_connection_t *hc, service_t *service) const char *str; size_t qsize; const char *name; + char addrbuf[50]; mc = muxer_container_txt2type(http_arg_get(&hc->hc_req_args, "mux")); if(mc == MC_UNKNOWN) { @@ -589,8 +591,9 @@ http_stream_service(http_connection_t *hc, service_t *service) flags = 0; } + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50); s = subscription_create_from_service(service, "HTTP", st, flags, - inet_ntoa(hc->hc_peer->sin_addr), + addrbuf, hc->hc_username, http_arg_get(&hc->hc_args, "User-Agent")); if(s) { @@ -624,10 +627,12 @@ http_stream_tdmi(http_connection_t *hc, th_dvb_mux_instance_t *tdmi) th_subscription_t *s; streaming_queue_t sq; const char *name; + char addrbuf[50]; streaming_queue_init(&sq, SMT_PACKET); + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50); s = dvb_subscription_create_from_tdmi(tdmi, "HTTP", &sq.sq_st, - inet_ntoa(hc->hc_peer->sin_addr), + addrbuf, hc->hc_username, http_arg_get(&hc->hc_args, "User-Agent")); name = strdupa(tdmi->tdmi_identifier); @@ -661,6 +666,7 @@ http_stream_channel(http_connection_t *hc, channel_t *ch) char *str; size_t qsize; const char *name; + char addrbuf[50]; mc = muxer_container_txt2type(http_arg_get(&hc->hc_req_args, "mux")); if(mc == MC_UNKNOWN) { @@ -687,8 +693,9 @@ http_stream_channel(http_connection_t *hc, channel_t *ch) flags = 0; } + tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50); s = subscription_create_from_channel(ch, priority, "HTTP", st, flags, - inet_ntoa(hc->hc_peer->sin_addr), + addrbuf, hc->hc_username, http_arg_get(&hc->hc_args, "User-Agent")); From 8ba3bbdc58c492ead416b3094526a231a909b589 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 05:32:02 +0100 Subject: [PATCH 6/8] Make access system ipv6 aware --- src/access.c | 158 +++++++++++++++++++++++++++++++++++++++++++-------- src/access.h | 2 + 2 files changed, 136 insertions(+), 24 deletions(-) diff --git a/src/access.c b/src/access.c index 7814025e..4be611df 100644 --- a/src/access.c +++ b/src/access.c @@ -149,6 +149,70 @@ access_ticket_verify(const char *id, const char *resource) return 0; } +/** + * + */ +static int +netmask_verify(access_entry_t *ae, struct sockaddr *src) +{ + int isv4v6 = 0; + uint32_t v4v6 = 0; + + if(src->sa_family == AF_INET6) + { + struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr); + uint32_t *a32 = (uint32_t*)in6->s6_addr; + if(a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000FFFFu) + { + isv4v6 = 1; + v4v6 = ntohl(a32[3]); + } + } + + if(ae->ae_ipv6 == 0 && src->sa_family == AF_INET) + { + struct sockaddr_in *in4 = (struct sockaddr_in *)src; + uint32_t b = ntohl(in4->sin_addr.s_addr); + return (b & ae->ae_netmask) == ae->ae_network; + } + else if(ae->ae_ipv6 == 0 && isv4v6) + { + return (v4v6 & ae->ae_netmask) == ae->ae_network; + } + else if(ae->ae_ipv6 && isv4v6) + { + return 0; + } + else if(ae->ae_ipv6 && src->sa_family == AF_INET6) + { + struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr); + uint8_t *a8 = (uint8_t*)in6->s6_addr; + uint8_t *m8 = (uint8_t*)ae->ae_ip6.s6_addr; + int slen = ae->ae_prefixlen; + uint32_t apos = 0; + uint8_t lastMask = (0xFFu << (8 - (slen % 8))); + + if(slen < 0 || slen > 128) + return 0; + + while(slen >= 8) + { + if(a8[apos] != m8[apos]) + return 0; + + apos += 1; + slen -= 8; + } + + if(slen == 0) + return 1; + + return (a8[apos] & lastMask) == (m8[apos] & lastMask); + } + + return 0; +} + /** * */ @@ -157,8 +221,6 @@ access_verify(const char *username, const char *password, struct sockaddr *src, uint32_t mask) { uint32_t bits = 0; - struct sockaddr_in *si = (struct sockaddr_in *)src; - uint32_t b = ntohl(si->sin_addr.s_addr); access_entry_t *ae; if(username != NULL && superuser_username != NULL && @@ -182,7 +244,7 @@ access_verify(const char *username, const char *password, continue; /* username/password mismatch */ } - if((b & ae->ae_netmask) != ae->ae_network) + if(!netmask_verify(ae, src)) continue; /* IP based access mismatches */ bits |= ae->ae_rights; @@ -200,8 +262,6 @@ access_get_hashed(const char *username, const uint8_t digest[20], const uint8_t *challenge, struct sockaddr *src, int *entrymatch) { - struct sockaddr_in *si = (struct sockaddr_in *)src; - uint32_t b = ntohl(si->sin_addr.s_addr); access_entry_t *ae; SHA_CTX shactx; uint8_t d[20]; @@ -226,7 +286,7 @@ access_get_hashed(const char *username, const uint8_t digest[20], if(!ae->ae_enabled) continue; - if((b & ae->ae_netmask) != ae->ae_network) + if(!netmask_verify(ae, src)) continue; /* IP based access mismatches */ SHA1_Init(&shactx); @@ -253,8 +313,6 @@ access_get_hashed(const char *username, const uint8_t digest[20], uint32_t access_get_by_addr(struct sockaddr *src) { - struct sockaddr_in *si = (struct sockaddr_in *)src; - uint32_t b = ntohl(si->sin_addr.s_addr); access_entry_t *ae; uint32_t r = 0; @@ -263,7 +321,7 @@ access_get_by_addr(struct sockaddr *src) if(ae->ae_username[0] != '*') continue; - if((b & ae->ae_netmask) != ae->ae_network) + if(!netmask_verify(ae, src)) continue; /* IP based access mismatches */ r |= ae->ae_rights; @@ -300,21 +358,50 @@ access_set_prefix(access_entry_t *ae, const char *prefix) return; strcpy(buf, prefix); - p = strchr(buf, '/'); - if(p) { - *p++ = 0; - prefixlen = atoi(p); - if(prefixlen > 32) - return; - } else { - prefixlen = 32; + + if(strchr(buf, ':') != NULL) + ae->ae_ipv6 = 1; + else + ae->ae_ipv6 = 0; + + if(ae->ae_ipv6) + { + p = strchr(buf, '/'); + if(p) + { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 128) + return; + } else { + prefixlen = 128; + } + + ae->ae_prefixlen = prefixlen; + inet_pton(AF_INET6, buf, &ae->ae_ip6); + + ae->ae_netmask = 0xffffffff; + ae->ae_network = 0x00000000; } + else + { + p = strchr(buf, '/'); + if(p) + { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 32) + return; + } else { + prefixlen = 32; + } - ae->ae_ip.s_addr = inet_addr(buf); - ae->ae_prefixlen = prefixlen; + ae->ae_ip.s_addr = inet_addr(buf); + ae->ae_prefixlen = prefixlen; - ae->ae_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; - ae->ae_network = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask; + ae->ae_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; + ae->ae_network = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask; + } } @@ -378,6 +465,7 @@ static htsmsg_t * access_record_build(access_entry_t *ae) { htsmsg_t *e = htsmsg_create_map(); + char addrbuf[50]; char buf[100]; htsmsg_add_u32(e, "enabled", !!ae->ae_enabled); @@ -386,7 +474,13 @@ access_record_build(access_entry_t *ae) htsmsg_add_str(e, "password", ae->ae_password); htsmsg_add_str(e, "comment", ae->ae_comment); - snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen); + if(ae->ae_ipv6) + { + inet_ntop(AF_INET6, &ae->ae_ip6, addrbuf, 50); + snprintf(buf, sizeof(buf), "%s/%d", addrbuf, ae->ae_prefixlen); + } + else + snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen); htsmsg_add_str(e, "prefix", buf); htsmsg_add_u32(e, "streaming", ae->ae_rights & ACCESS_STREAMING ? 1 : 0); @@ -558,17 +652,33 @@ access_init(int createdefault) ae = access_entry_find(NULL, 1); free(ae->ae_comment); - ae->ae_comment = strdup("Default access entry"); + ae->ae_comment = strdup("Default IPv6 access entry"); ae->ae_enabled = 1; ae->ae_rights = 0xffffffff; + ae->ae_ipv6 = 1; + + r = access_record_build(ae); + dtable_record_store(dt, ae->ae_id, r); + htsmsg_destroy(r); + + ae = access_entry_find(NULL, 1); + + free(ae->ae_comment); + ae->ae_comment = strdup("Default IPv4 access entry"); + + ae->ae_enabled = 1; + ae->ae_rights = 0xffffffff; + + ae->ae_ipv6 = 0; + r = access_record_build(ae); dtable_record_store(dt, ae->ae_id, r); htsmsg_destroy(r); tvhlog(LOG_WARNING, "accesscontrol", - "Created default wide open access controle entry"); + "Created default wide open access controle entrys"); } /* Load superuser account */ diff --git a/src/access.h b/src/access.h index 35bb1d83..3562b0ac 100644 --- a/src/access.h +++ b/src/access.h @@ -31,7 +31,9 @@ typedef struct access_entry { char *ae_username; char *ae_password; char *ae_comment; + int ae_ipv6; struct in_addr ae_ip; + struct in6_addr ae_ip6; int ae_prefixlen; int ae_enabled; From 3b758e5ce7e6587aeffb7280b863c636ad0f3b20 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 12:32:54 +0100 Subject: [PATCH 7/8] Add commandline option to switch on IPv6 support --- src/main.c | 7 ++++--- src/tcp.c | 8 ++++++-- src/tcp.h | 4 +++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index c6e0254d..40261213 100644 --- a/src/main.c +++ b/src/main.c @@ -359,7 +359,8 @@ main(int argc, char **argv) opt_debug = 0, opt_syslog = 0, opt_uidebug = 0, - opt_abort = 0; + opt_abort = 0, + opt_ipv6 = 0; const char *opt_config = NULL, *opt_user = NULL, *opt_group = NULL, @@ -391,8 +392,8 @@ main(int argc, char **argv) { 'a', "adapters", "Use only specified DVB adapters", OPT_STR, &opt_dvb_adapters }, #endif - { 0, NULL, "Server Connectivity", OPT_BOOL, NULL }, + { '6', "ipv6", "Listen on IPv6", OPT_BOOL, &opt_ipv6 }, { 0, "http_port", "Specify alternative http port", OPT_INT, &tvheadend_webui_port }, { 0, "http_root", "Specify alternative http webroot", @@ -606,7 +607,7 @@ main(int argc, char **argv) timeshift_init(); #endif - tcp_server_init(); + tcp_server_init(opt_ipv6); http_server_init(); webui_init(); diff --git a/src/tcp.c b/src/tcp.c index 3653e8b2..5ccf1bac 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -35,6 +35,7 @@ #include "tcp.h" #include "tvheadend.h" +int tcp_preferred_address_family = AF_INET; /** * @@ -526,7 +527,7 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque) ressave = res; while(res) { - if(res->ai_family == AF_INET6) + if(res->ai_family == tcp_preferred_address_family) { use = res; break; @@ -574,10 +575,13 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque) * */ void -tcp_server_init(void) +tcp_server_init(int opt_ipv6) { pthread_t tid; + if(opt_ipv6) + tcp_preferred_address_family = AF_INET6; + tcp_server_epoll_fd = epoll_create(10); pthread_create(&tid, NULL, tcp_server_loop, NULL); } diff --git a/src/tcp.h b/src/tcp.h index 187a9d57..0c061e43 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -21,7 +21,9 @@ #include "htsbuf.h" -void tcp_server_init(void); +extern int tcp_preferred_address_family; + +void tcp_server_init(int opt_ipv6); int tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout); From 89c3271368cd2807e1976f8dc7314bbe4ca32b27 Mon Sep 17 00:00:00 2001 From: BtbN Date: Tue, 15 Jan 2013 15:27:44 +0100 Subject: [PATCH 8/8] Convert prefix to a , seperated list of multiple prefixes --- src/access.c | 246 +++++++++++++++++++++++++++++++-------------------- src/access.h | 21 +++-- 2 files changed, 163 insertions(+), 104 deletions(-) diff --git a/src/access.c b/src/access.c index 4be611df..514e8707 100644 --- a/src/access.c +++ b/src/access.c @@ -155,6 +155,7 @@ access_ticket_verify(const char *id, const char *resource) static int netmask_verify(access_entry_t *ae, struct sockaddr *src) { + access_ipmask_t *ai; int isv4v6 = 0; uint32_t v4v6 = 0; @@ -169,45 +170,48 @@ netmask_verify(access_entry_t *ae, struct sockaddr *src) } } - if(ae->ae_ipv6 == 0 && src->sa_family == AF_INET) + LIST_FOREACH(ai, &ae->ae_ipmasks, ai_link) { - struct sockaddr_in *in4 = (struct sockaddr_in *)src; - uint32_t b = ntohl(in4->sin_addr.s_addr); - return (b & ae->ae_netmask) == ae->ae_network; - } - else if(ae->ae_ipv6 == 0 && isv4v6) - { - return (v4v6 & ae->ae_netmask) == ae->ae_network; - } - else if(ae->ae_ipv6 && isv4v6) - { - return 0; - } - else if(ae->ae_ipv6 && src->sa_family == AF_INET6) - { - struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr); - uint8_t *a8 = (uint8_t*)in6->s6_addr; - uint8_t *m8 = (uint8_t*)ae->ae_ip6.s6_addr; - int slen = ae->ae_prefixlen; - uint32_t apos = 0; - uint8_t lastMask = (0xFFu << (8 - (slen % 8))); - - if(slen < 0 || slen > 128) - return 0; - - while(slen >= 8) + if(ai->ai_ipv6 == 0 && src->sa_family == AF_INET) { - if(a8[apos] != m8[apos]) - return 0; - - apos += 1; - slen -= 8; + struct sockaddr_in *in4 = (struct sockaddr_in *)src; + uint32_t b = ntohl(in4->sin_addr.s_addr); + if((b & ai->ai_netmask) == ai->ai_network) + return 1; } + else if(ai->ai_ipv6 == 0 && isv4v6) + { + if((v4v6 & ai->ai_netmask) == ai->ai_network) + return 1; + } + else if(ai->ai_ipv6 && isv4v6) + { + continue; + } + else if(ai->ai_ipv6 && src->sa_family == AF_INET6) + { + struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr); + uint8_t *a8 = (uint8_t*)in6->s6_addr; + uint8_t *m8 = (uint8_t*)ai->ai_ip6.s6_addr; + int slen = ai->ai_prefixlen; + uint32_t apos = 0; + uint8_t lastMask = (0xFFu << (8 - (slen % 8))); - if(slen == 0) - return 1; + if(slen < 0 || slen > 128) + continue; - return (a8[apos] & lastMask) == (m8[apos] & lastMask); + while(slen >= 8) + { + if(a8[apos] != m8[apos]) + continue; + + apos += 1; + slen -= 8; + } + + if(slen == 0 || (a8[apos] & lastMask) == (m8[apos] & lastMask)) + return 1; + } } return 0; @@ -351,56 +355,89 @@ static void access_set_prefix(access_entry_t *ae, const char *prefix) { char buf[100]; + char tokbuf[4096]; int prefixlen; - char *p; + char *p, *tok, *saveptr; + access_ipmask_t *ai; - if(strlen(prefix) > 90) - return; - - strcpy(buf, prefix); - - if(strchr(buf, ':') != NULL) - ae->ae_ipv6 = 1; - else - ae->ae_ipv6 = 0; - - if(ae->ae_ipv6) + while((ai = LIST_FIRST(&ae->ae_ipmasks)) != NULL) { - p = strchr(buf, '/'); - if(p) - { - *p++ = 0; - prefixlen = atoi(p); - if(prefixlen > 128) - return; - } else { - prefixlen = 128; - } - - ae->ae_prefixlen = prefixlen; - inet_pton(AF_INET6, buf, &ae->ae_ip6); - - ae->ae_netmask = 0xffffffff; - ae->ae_network = 0x00000000; + LIST_REMOVE(ai, ai_link); + free(ai); } - else + + strncpy(tokbuf, prefix, 4095); + tokbuf[4095] = 0; + tok = strtok_r(tokbuf, ",;| ", &saveptr); + + while(tok != NULL) { - p = strchr(buf, '/'); - if(p) + ai = calloc(1, sizeof(access_ipmask_t)); + + if(strlen(tok) > 90 || strlen(tok) == 0) { - *p++ = 0; - prefixlen = atoi(p); - if(prefixlen > 32) - return; - } else { - prefixlen = 32; + free(ai); + tok = strtok_r(NULL, ",;| ", &saveptr); + continue; } - ae->ae_ip.s_addr = inet_addr(buf); - ae->ae_prefixlen = prefixlen; + strcpy(buf, tok); - ae->ae_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; - ae->ae_network = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask; + if(strchr(buf, ':') != NULL) + ai->ai_ipv6 = 1; + else + ai->ai_ipv6 = 0; + + if(ai->ai_ipv6) + { + p = strchr(buf, '/'); + if(p) + { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 128) + { + free(ai); + tok = strtok_r(NULL, ",;| ", &saveptr); + continue; + } + } else { + prefixlen = 128; + } + + ai->ai_prefixlen = prefixlen; + inet_pton(AF_INET6, buf, &ai->ai_ip6); + + ai->ai_netmask = 0xffffffff; + ai->ai_network = 0x00000000; + } + else + { + p = strchr(buf, '/'); + if(p) + { + *p++ = 0; + prefixlen = atoi(p); + if(prefixlen > 32) + { + free(ai); + tok = strtok_r(NULL, ",;| ", &saveptr); + continue; + } + } else { + prefixlen = 32; + } + + ai->ai_ip.s_addr = inet_addr(buf); + ai->ai_prefixlen = prefixlen; + + ai->ai_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0; + ai->ai_network = ntohl(ai->ai_ip.s_addr) & ai->ai_netmask; + } + + LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link); + + tok = strtok_r(NULL, ",;| ", &saveptr); } } @@ -450,6 +487,14 @@ access_entry_find(const char *id, int create) static void access_entry_destroy(access_entry_t *ae) { + access_ipmask_t *ai; + + while((ai = LIST_FIRST(&ae->ae_ipmasks)) != NULL) + { + LIST_REMOVE(ai, ai_link); + free(ai); + } + free(ae->ae_id); free(ae->ae_username); free(ae->ae_password); @@ -465,8 +510,12 @@ static htsmsg_t * access_record_build(access_entry_t *ae) { htsmsg_t *e = htsmsg_create_map(); + access_ipmask_t *ai; char addrbuf[50]; - char buf[100]; + char buf[4096]; + int pos = 0; + + memset(buf, 0, 4096); htsmsg_add_u32(e, "enabled", !!ae->ae_enabled); @@ -474,14 +523,22 @@ access_record_build(access_entry_t *ae) htsmsg_add_str(e, "password", ae->ae_password); htsmsg_add_str(e, "comment", ae->ae_comment); - if(ae->ae_ipv6) + LIST_FOREACH(ai, &ae->ae_ipmasks, ai_link) { - inet_ntop(AF_INET6, &ae->ae_ip6, addrbuf, 50); - snprintf(buf, sizeof(buf), "%s/%d", addrbuf, ae->ae_prefixlen); + if(sizeof(buf)-pos <= 0) + break; + + if(ai->ai_ipv6) + { + inet_ntop(AF_INET6, &ai->ai_ip6, addrbuf, 50); + pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", addrbuf, ai->ai_prefixlen); + } + else + { + pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", inet_ntoa(ai->ai_ip), ai->ai_prefixlen); + } } - else - snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen); - htsmsg_add_str(e, "prefix", buf); + htsmsg_add_str(e, "prefix", buf + 1); htsmsg_add_u32(e, "streaming", ae->ae_rights & ACCESS_STREAMING ? 1 : 0); htsmsg_add_u32(e, "dvr" , ae->ae_rights & ACCESS_RECORDER ? 1 : 0); @@ -631,6 +688,7 @@ access_init(int createdefault) dtable_t *dt; htsmsg_t *r, *m; access_entry_t *ae; + access_ipmask_t *ai; const char *s; static struct { @@ -652,33 +710,25 @@ access_init(int createdefault) ae = access_entry_find(NULL, 1); free(ae->ae_comment); - ae->ae_comment = strdup("Default IPv6 access entry"); + ae->ae_comment = strdup("Default access entry"); ae->ae_enabled = 1; ae->ae_rights = 0xffffffff; - ae->ae_ipv6 = 1; + ai = calloc(1, sizeof(access_ipmask_t)); + ai->ai_ipv6 = 0; + LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link); - r = access_record_build(ae); - dtable_record_store(dt, ae->ae_id, r); - htsmsg_destroy(r); - - ae = access_entry_find(NULL, 1); - - free(ae->ae_comment); - ae->ae_comment = strdup("Default IPv4 access entry"); - - ae->ae_enabled = 1; - ae->ae_rights = 0xffffffff; - - ae->ae_ipv6 = 0; + ai = calloc(1, sizeof(access_ipmask_t)); + ai->ai_ipv6 = 1; + LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link); r = access_record_build(ae); dtable_record_store(dt, ae->ae_id, r); htsmsg_destroy(r); tvhlog(LOG_WARNING, "accesscontrol", - "Created default wide open access controle entrys"); + "Created default wide open access controle entry"); } /* Load superuser account */ diff --git a/src/access.h b/src/access.h index 3562b0ac..466e380f 100644 --- a/src/access.h +++ b/src/access.h @@ -20,6 +20,20 @@ #define ACCESS_H_ +typedef struct access_ipmask { + LIST_ENTRY(access_ipmask) ai_link; + + int ai_ipv6; + + struct in_addr ai_ip; + struct in6_addr ai_ip6; + + int ai_prefixlen; + + uint32_t ai_network; + uint32_t ai_netmask; +} access_ipmask_t; + TAILQ_HEAD(access_entry_queue, access_entry); extern struct access_entry_queue access_entries; @@ -31,17 +45,12 @@ typedef struct access_entry { char *ae_username; char *ae_password; char *ae_comment; - int ae_ipv6; - struct in_addr ae_ip; - struct in6_addr ae_ip6; - int ae_prefixlen; int ae_enabled; uint32_t ae_rights; - uint32_t ae_network; /* derived from ae_ip */ - uint32_t ae_netmask; /* derived from ae_prefixlen */ + LIST_HEAD(, access_ipmask) ae_ipmasks; } access_entry_t; TAILQ_HEAD(access_ticket_queue, access_ticket);