From f0407d780e9c88367c56ff394a3a4cb5fbb8a783 Mon Sep 17 00:00:00 2001 From: "F. Duncanh" Date: Sun, 12 May 2024 01:24:38 -0400 Subject: [PATCH] add zone_id to link-local ipv6 addresses --- lib/httpd.c | 15 +++++++++------ lib/httpd.h | 3 ++- lib/netutils.c | 8 +++++--- lib/netutils.h | 2 +- lib/raop.c | 35 +++++++++++++---------------------- lib/raop.h | 4 ++-- lib/raop_handlers.h | 37 ++++++++++++++++--------------------- lib/utils.c | 26 ++++++++++++++++++++++++++ lib/utils.h | 3 ++- 9 files changed, 76 insertions(+), 57 deletions(-) diff --git a/lib/httpd.c b/lib/httpd.c index e1e3704..a4adf21 100644 --- a/lib/httpd.c +++ b/lib/httpd.c @@ -115,7 +115,8 @@ httpd_remove_connection(httpd_t *httpd, http_connection_t *connection) } static int -httpd_add_connection(httpd_t *httpd, int fd, unsigned char *local, int local_len, unsigned char *remote, int remote_len) +httpd_add_connection(httpd_t *httpd, int fd, unsigned char *local, int local_len, unsigned char *remote, + int remote_len, unsigned int zone_id) { void *user_data; int i; @@ -131,7 +132,7 @@ httpd_add_connection(httpd_t *httpd, int fd, unsigned char *local, int local_len return -1; } - user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len); + user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len, zone_id); if (!user_data) { logger_log(httpd->logger, LOGGER_ERR, "Error initializing HTTP request handler"); return -1; @@ -152,6 +153,7 @@ httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6) struct sockaddr_storage local_saddr; socklen_t local_saddrlen; unsigned char *local, *remote; + unsigned int local_zone_id, remote_zone_id; int local_len, remote_len; int ret, fd; @@ -172,9 +174,10 @@ httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6) logger_log(httpd->logger, LOGGER_INFO, "Accepted %s client on socket %d", (is_ipv6 ? "IPv6" : "IPv4"), fd); - local = netutils_get_address(&local_saddr, &local_len); - remote = netutils_get_address(&remote_saddr, &remote_len); - + local = netutils_get_address(&local_saddr, &local_len, &local_zone_id); + remote = netutils_get_address(&remote_saddr, &remote_len, &remote_zone_id); + assert (local_zone_id == remote_zone_id); + #ifdef NOHOLD /* remove existing connections to make way for new connections: * this will only occur if max_connections > 2 */ @@ -190,7 +193,7 @@ httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6) } #endif - ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len); + ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len, local_zone_id); if (ret == -1) { shutdown(fd, SHUT_RDWR); closesocket(fd); diff --git a/lib/httpd.h b/lib/httpd.h index fc184e1..a606a6a 100644 --- a/lib/httpd.h +++ b/lib/httpd.h @@ -23,7 +23,8 @@ typedef struct httpd_s httpd_t; struct httpd_callbacks_s { void* opaque; - void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote, int remotelen); + void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote, + int remotelen, unsigned int zone_id); void (*conn_request)(void *ptr, http_request_t *request, http_response_t **response); void (*conn_destroy)(void *ptr); }; diff --git a/lib/netutils.c b/lib/netutils.c index 5832c43..642efba 100644 --- a/lib/netutils.c +++ b/lib/netutils.c @@ -53,17 +53,17 @@ netutils_cleanup() } unsigned char * -netutils_get_address(void *sockaddr, int *length) +netutils_get_address(void *sockaddr, int *length, unsigned int *zone_id) { unsigned char ipv4_prefix[] = { 0,0,0,0,0,0,0,0,0,0,255,255 }; struct sockaddr *address = sockaddr; assert(address); assert(length); - + assert(zone_id); if (address->sa_family == AF_INET) { struct sockaddr_in *sin; - + *zone_id = 0; sin = (struct sockaddr_in *)address; *length = sizeof(sin->sin_addr.s_addr); return (unsigned char *)&sin->sin_addr.s_addr; @@ -73,9 +73,11 @@ netutils_get_address(void *sockaddr, int *length) sin6 = (struct sockaddr_in6 *)address; if (!memcmp(sin6->sin6_addr.s6_addr, ipv4_prefix, 12)) { /* Actually an embedded IPv4 address */ + *zone_id = 0; *length = sizeof(sin6->sin6_addr.s6_addr)-12; return (sin6->sin6_addr.s6_addr+12); } + *zone_id = (unsigned int) sin6->sin6_scope_id; *length = sizeof(sin6->sin6_addr.s6_addr); return sin6->sin6_addr.s6_addr; } diff --git a/lib/netutils.h b/lib/netutils.h index 63854ad..e64c638 100644 --- a/lib/netutils.h +++ b/lib/netutils.h @@ -19,7 +19,7 @@ int netutils_init(); void netutils_cleanup(); int netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp); -unsigned char *netutils_get_address(void *sockaddr, int *length); +unsigned char *netutils_get_address(void *sockaddr, int *length, unsigned int *zone_id); int netutils_parse_address(int family, const char *src, void *dst, int dstlen); #endif diff --git a/lib/raop.c b/lib/raop.c index bc9554e..9a249bc 100644 --- a/lib/raop.c +++ b/lib/raop.c @@ -88,6 +88,8 @@ struct raop_conn_s { unsigned char *remote; int remotelen; + unsigned int zone_id; + bool have_active_remote; }; typedef struct raop_conn_s raop_conn_t; @@ -95,10 +97,10 @@ typedef struct raop_conn_s raop_conn_t; #include "raop_handlers.h" static void * -conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remote, int remotelen) { +conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remote, int remotelen, unsigned int zone_id) { raop_t *raop = opaque; raop_conn_t *conn; - + char ip_address[40]; assert(raop); conn = calloc(1, sizeof(raop_conn_t)); @@ -122,26 +124,12 @@ conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remot return NULL; } - if (locallen == 4) { - logger_log(conn->raop->logger, LOGGER_INFO, - "Local: %d.%d.%d.%d", - local[0], local[1], local[2], local[3]); - } else if (locallen == 16) { - logger_log(conn->raop->logger, LOGGER_INFO, - "Local: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - local[0], local[1], local[2], local[3], local[4], local[5], local[6], local[7], - local[8], local[9], local[10], local[11], local[12], local[13], local[14], local[15]); - } - if (remotelen == 4) { - logger_log(conn->raop->logger, LOGGER_INFO, - "Remote: %d.%d.%d.%d", - remote[0], remote[1], remote[2], remote[3]); - } else if (remotelen == 16) { - logger_log(conn->raop->logger, LOGGER_INFO, - "Remote: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - remote[0], remote[1], remote[2], remote[3], remote[4], remote[5], remote[6], remote[7], - remote[8], remote[9], remote[10], remote[11], remote[12], remote[13], remote[14], remote[15]); - } + + utils_ipaddress_to_string(locallen, local, zone_id, ip_address, (int) sizeof(ip_address)); + logger_log(conn->raop->logger, LOGGER_INFO, "Local : %s", ip_address); + + utils_ipaddress_to_string(remotelen, remote, zone_id, ip_address, (int) sizeof(ip_address)); + logger_log(conn->raop->logger, LOGGER_INFO, "Remote: %s", ip_address); conn->local = malloc(locallen); assert(conn->local); @@ -151,8 +139,11 @@ conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remot assert(conn->remote); memcpy(conn->remote, remote, remotelen); + conn->zone_id = zone_id; + conn->locallen = locallen; conn->remotelen = remotelen; + conn->have_active_remote = false; if (raop->callbacks.conn_init) { diff --git a/lib/raop.h b/lib/raop.h index 1982773..43a7a4e 100644 --- a/lib/raop.h +++ b/lib/raop.h @@ -65,8 +65,8 @@ struct raop_callbacks_s { void (*export_dacp) (void *cls, const char *active_remote, const char *dacp_id); }; typedef struct raop_callbacks_s raop_callbacks_t; -raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len, - unsigned short timing_rport, timing_protocol_t *time_protocol); +raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, + int remote_addr_len, unsigned short timing_rport, timing_protocol_t *time_protocol); RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks); RAOP_API int raop_init2(raop_t *raop, int max_clients, const char *device_id, const char *keyfile); diff --git a/lib/raop_handlers.h b/lib/raop_handlers.h index c418f70..b2ba5c9 100644 --- a/lib/raop_handlers.h +++ b/lib/raop_handlers.h @@ -737,28 +737,23 @@ raop_handler_setup(raop_conn_t *conn, conn->raop_ntp = NULL; conn->raop_rtp = NULL; conn->raop_rtp_mirror = NULL; - if (conn->remotelen == 4 || conn->remotelen == 16) { - char remote[40]; - if (conn->remotelen == 4) { - /* IPV4 */ - snprintf(remote, sizeof(remote), "%d.%d.%d.%d", conn->remote[0], conn->remote[1], - conn->remote[2], conn->remote[3]); - } else { - /*IPV6*/ - snprintf(remote, sizeof(remote), "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - conn->remote[0], conn->remote[1], conn->remote[2], conn->remote[3], - conn->remote[4], conn->remote[5], conn->remote[6], conn->remote[7], - conn->remote[8], conn->remote[9], conn->remote[10], conn->remote[11], - conn->remote[12], conn->remote[13], conn->remote[14], conn->remote[15]); - } - conn->raop_ntp = raop_ntp_init(conn->raop->logger, &conn->raop->callbacks, remote, - conn->remotelen, (unsigned short) timing_rport, &time_protocol); - raop_ntp_start(conn->raop_ntp, &timing_lport, conn->raop->max_ntp_timeouts); - conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, - remote, conn->remotelen, aeskey, aesiv); - conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks, - conn->raop_ntp, remote, conn->remotelen, aeskey); + char remote[40]; + int len = utils_ipaddress_to_string(conn->remotelen, conn->remote, conn->zone_id, remote, (int) sizeof(remote)); + if (!len || len > sizeof(remote)) { + char *str = utils_data_to_string(conn->remote, conn->remotelen, 16); + logger_log(conn->raop->logger, LOGGER_ERR, "failed to extract valid client ip address:\n" + "*** UxPlay will be unable to send communications to client.\n" + "*** address length %d, zone_id %u address data:\n%sparser returned \"%s\"\n", + conn->remotelen, conn->zone_id, str, remote); + free(str); } + conn->raop_ntp = raop_ntp_init(conn->raop->logger, &conn->raop->callbacks, remote, + conn->remotelen, (unsigned short) timing_rport, &time_protocol); + raop_ntp_start(conn->raop_ntp, &timing_lport, conn->raop->max_ntp_timeouts); + conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, + remote, conn->remotelen, aeskey, aesiv); + conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks, + conn->raop_ntp, remote, conn->remotelen, aeskey); plist_t res_event_port_node = plist_new_uint(conn->raop->port); plist_t res_timing_port_node = plist_new_uint(timing_lport); diff --git a/lib/utils.c b/lib/utils.c index 561e79b..f6c89f0 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -256,3 +256,29 @@ void ntp_timestamp_to_seconds(uint64_t ntp_timestamp, char *timestamp, size_t ma strftime(timestamp, 3, "%S", &ts); snprintf(timestamp + 2, 11,".%9.9lu", (unsigned long) ntp_timestamp % SECOND_IN_NSECS); } + +int utils_ipaddress_to_string(int addresslen, const unsigned char *address, unsigned int zone_id, char *string, int sizeof_string) { + int ret = 0; + unsigned char ipv6_link_local_prefix[] = { 0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + assert(sizeof_string > 0); + assert(string); + if (addresslen != 4 && addresslen != 16) { //invalid address length (only ipv4 and ipv6 allowed) + string[0] = '\0'; + } + if (addresslen == 4) { /* IPV4 */ + ret = snprintf(string, sizeof_string, "%d.%d.%d.%d", address[0], address[1], address[2], address[3]); + } else if (zone_id) { /* IPV6 link-local */ + if (memcmp(address, ipv6_link_local_prefix, 8)) { + string[0] = '\0'; //only link-local ipv6 addresses can have a zone_id + } else { + ret = snprintf(string, sizeof_string, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x%%%u", + address[8], address[9], address[10], address[11], + address[12], address[13], address[14], address[15], zone_id); + } + } else { /* IPV6 standard*/ + ret = snprintf(string, sizeof_string, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + address[0], address[1], address[2], address[3], address[4], address[5], address[6], address[7], + address[8], address[9], address[10], address[11], address[12], address[13], address[14], address[15]); + } + return ret; +} diff --git a/lib/utils.h b/lib/utils.h index 671115a..be5db30 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -30,5 +30,6 @@ char *utils_data_to_string(const unsigned char *data, int datalen, int chars_per char *utils_data_to_text(const char *data, int datalen); void ntp_timestamp_to_time(uint64_t ntp_timestamp, char *timestamp, size_t maxsize); void ntp_timestamp_to_seconds(uint64_t ntp_timestamp, char *timestamp, size_t maxsize); - +int utils_ipaddress_to_string(int addresslen, const unsigned char *address, + unsigned int zone_id, char *string, int len); #endif