add zone_id to link-local ipv6 addresses

This commit is contained in:
F. Duncanh
2024-05-12 01:24:38 -04:00
parent cafc03e0df
commit f0407d780e
9 changed files with 76 additions and 57 deletions

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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