diff --git a/src/satip/rtsp.c b/src/satip/rtsp.c index 7b366c8..8f2aae8 100644 --- a/src/satip/rtsp.c +++ b/src/satip/rtsp.c @@ -92,6 +92,7 @@ static pthread_mutex_t rtsp_lock; static void rtsp_close_session(session_t *rs); static void rtsp_free_session(session_t *rs); +static char any_ip[] = "127.0.0.1\0"; /* * @@ -319,6 +320,44 @@ rtsp_parse_args(http_connection_t *hc, char *u) /* * */ +static inline int +rtsp_announced_port(struct sockaddr_storage *peer, struct sockaddr_storage *self) +{ + int used_port = 0; + + if (satip_server_conf.satip_nat_name_force || !check_is_local_address(peer,self)) { + used_port = (rtsp_nat_port > 0)? rtsp_nat_port : rtsp_port; + } else { + used_port = rtsp_port; + } + + return used_port; +} + +/* + * + */ +static inline char * +rtsp_announced_ip(struct sockaddr_storage *peer, struct sockaddr_storage *self) +{ + char *used_ip; + + if (satip_server_conf.satip_nat_name_force || !check_is_local_address(peer,self)) { + used_ip = rtsp_nat_ip; + } else { + used_ip = rtsp_ip; + } + + if (used_ip[0] == '*' || used_ip[0] == '\0' || used_ip == NULL) { + used_ip = any_ip; + } + + return used_ip; +} + +/* + * + */ static void rtsp_slave_add (session_t *rs, mpegts_service_t *master, mpegts_service_t *slave) @@ -1322,9 +1361,9 @@ rtsp_process_describe(http_connection_t *hc) char *u = tvh_strdupa(hc->hc_url); session_t *rs; htsbuf_queue_t q; - char buf[96]; + char buf[96], *used_ip = NULL; int r = HTTP_STATUS_BAD_REQUEST; - int stream, first = 1, valid; + int stream, first = 1, valid, used_port; htsbuf_queue_init(&q, 0); @@ -1381,10 +1420,16 @@ rtsp_process_describe(http_connection_t *hc) http_arg_init(&args); if (hc->hc_session) http_arg_set(&args, "Session", hc->hc_session); - if (stream > 0) - snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", rtsp_ip, stream); + used_port = rtsp_announced_port(hc->hc_peer,hc->hc_self); + used_ip = rtsp_announced_ip(hc->hc_peer,hc->hc_self); + if ((stream > 0) && (used_port != 554)) + snprintf(buf, sizeof(buf), "rtsp://%s:%d/stream=%i", used_ip, used_port, stream); + else if ((stream > 0) && (used_port == 554)) + snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", used_ip, stream); + else if (used_port != 554) + snprintf(buf, sizeof(buf), "rtsp://%s:%d", used_ip, used_port); else - snprintf(buf, sizeof(buf), "rtsp://%s", rtsp_ip); + snprintf(buf, sizeof(buf), "rtsp://%s", used_ip); http_arg_set(&args, "Content-Base", buf); http_send_begin(hc); http_send_header(hc, HTTP_STATUS_OK, "application/sdp", q.hq_size, @@ -1408,8 +1453,8 @@ static int rtsp_process_play(http_connection_t *hc, int cmd) { session_t *rs; - int errcode = HTTP_STATUS_BAD_REQUEST, valid = 0, i, stream; - char buf[256], *u = tvh_strdupa(hc->hc_url); + int errcode = HTTP_STATUS_BAD_REQUEST, valid = 0, i, stream, used_port; + char buf[256], *u = tvh_strdupa(hc->hc_url), *used_ip = NULL; http_arg_list_t args; http_arg_init(&args); @@ -1467,10 +1512,12 @@ rtsp_process_play(http_connection_t *hc, int cmd) snprintf(buf, sizeof(buf), "%d", rs->stream); http_arg_set(&args, "com.ses.streamID", buf); } else { - if (rtsp_port != 554) - snprintf(buf, sizeof(buf), "url=rtsp://%s:%d/stream=%d", rtsp_ip, rtsp_port, rs->stream); + used_port = rtsp_announced_port(hc->hc_peer,hc->hc_self); + used_ip = rtsp_announced_ip(hc->hc_peer,hc->hc_self); + if (used_port != 554) + snprintf(buf, sizeof(buf), "url=rtsp://%s:%d/stream=%d", used_ip, used_port, rs->stream); else - snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", rtsp_ip, rs->stream); + snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", used_ip, rs->stream); http_arg_set(&args, "RTP-Info", buf); } diff --git a/src/satip/server.c b/src/satip/server.c index 64397e5..57d8487 100644 --- a/src/satip/server.c +++ b/src/satip/server.c @@ -777,6 +777,19 @@ const idclass_t satip_server_class = { .group = 2, }, { + .type = PT_BOOL, + .id = "satip_nat_name_force", + .name = N_("Force RTSP announcement of the external (NAT) ip:port"), + .desc = N_("Advertise only NAT address and port in RTSP commands," + "even for local connections."), + .off = offsetof(struct satip_server_conf, satip_nat_name_force), + .opts = PO_EXPERT, + .group = 2, + }, + + + + { .type = PT_U32, .id = "satip_iptv_sig_level", .name = N_("IPTV signal level"), diff --git a/src/satip/server.h b/src/satip/server.h index eb11ca6..f72c01a 100644 --- a/src/satip/server.h +++ b/src/satip/server.h @@ -65,6 +65,7 @@ struct satip_server_conf { int satip_atsc_c; char *satip_nat_ip; int satip_nat_rtsp; + int satip_nat_name_force; }; extern struct satip_server_conf satip_server_conf; diff --git a/src/tcp.c b/src/tcp.c index e0ccd0f..13be113 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "tvheadend.h" #include "tcp.h" @@ -73,6 +75,121 @@ socket_set_dscp(int sockfd, uint32_t dscp, char *errbuf, size_t errbufsize) /** * */ +inline int +check_equal_v4(const struct in_addr * a, + const struct in_addr * b) +{ + return (a->s_addr == b->s_addr); +} + +/** + * + */ +inline int +check_equal_v6(const struct in6_addr * a, + const struct in6_addr * b) +{ + return (memcmp(a->s6_addr, b->s6_addr, 16) == 0) ? 1 : 0; +} + +/** + * + */ +inline int +check_in_network_v4(const struct in_addr * network, + const struct in_addr * mask, + const struct in_addr * address) +{ + return ((address->s_addr & mask->s_addr) == (network->s_addr & mask->s_addr)); +} + +/** + * + */ +inline int +check_in_network_v6(const struct in6_addr * network, + const struct in6_addr * mask, + const struct in6_addr * address) +{ + unsigned int i; + for (i=0; is_addr == INADDR_ANY); +} + +/** + * + */ +inline int +check_is_any_v6(const struct in6_addr * address) +{ + return (check_equal_v6(address,&in6addr_any)); +} + +/** + * + */ +int +check_is_local_address(const struct sockaddr_storage *peer, const struct sockaddr_storage *local) +{ + struct ifaddrs *iflist, *ifdev = NULL; + struct sockaddr_storage *ifaddr, *ifnetmask; + int any_address = 0; + + if ( (local->ss_family == AF_INET && check_is_any_v4(&((struct sockaddr_in *)local)->sin_addr) ) || + (local->ss_family == AF_INET6 && check_is_any_v6(&((struct sockaddr_in6 *)local)->sin6_addr) ) ) { + any_address = 1; + } + tvhdebug(LS_SATIPS, "tcp_is_local_address(): ANY=%i",any_address); + + // Note: Not all platforms have getifaddrs() + // See http://docs.freeswitch.org/switch__utils_8c_source.html + if (!local || !peer || getifaddrs(&iflist) < 0) return 0; + + for (ifdev = iflist; ifdev; ifdev = ifdev->ifa_next) { + ifaddr = (struct sockaddr_storage *)(ifdev->ifa_addr); + ifnetmask = (struct sockaddr_storage *)(ifdev->ifa_netmask); + + if (ifaddr && ifnetmask && ifaddr->ss_family == local->ss_family && ifaddr->ss_family == peer->ss_family) { + + if (ifaddr->ss_family == AF_INET) { + if ((any_address || check_equal_v4( &((struct sockaddr_in *)ifaddr)->sin_addr, &((struct sockaddr_in *)local)->sin_addr )) + && check_in_network_v4( &((struct sockaddr_in *)ifaddr)->sin_addr, + &((struct sockaddr_in *)ifnetmask)->sin_addr, + &((struct sockaddr_in *)peer)->sin_addr) ) { + freeifaddrs(iflist); + return 1; + } + } else if (ifaddr->ss_family == AF_INET6) { + if ((any_address || check_equal_v6( &((struct sockaddr_in6 *)ifaddr)->sin6_addr, &((struct sockaddr_in6 *)local)->sin6_addr )) + && check_in_network_v6( &((struct sockaddr_in6 *)ifaddr)->sin6_addr, + &((struct sockaddr_in6 *)ifnetmask)->sin6_addr, + &((struct sockaddr_in6 *)peer)->sin6_addr) ) { + freeifaddrs(iflist); + return 1; + } + } + } + } + freeifaddrs(iflist); + return 0; +} + +/** + * + */ int tcp_connect(const char *hostname, int port, const char *bindaddr, char *errbuf, size_t errbufsize, int timeout) diff --git a/src/tcp.h b/src/tcp.h index 64463bb..e7501c4 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -58,6 +58,18 @@ void tcp_server_preinit(int opt_ipv6); void tcp_server_init(void); void tcp_server_done(void); +int check_equal_v4(const struct in_addr * a, const struct in_addr * b); +int check_equal_v6(const struct in6_addr * a, const struct in6_addr * b); +int check_in_network_v4(const struct in_addr * network, + const struct in_addr * mask, + const struct in_addr * address); +int check_in_network_v6(const struct in6_addr * network, + const struct in6_addr * mask, + const struct in6_addr * address); +int check_is_any_v4(const struct in_addr * address); +int check_is_any_v6(const struct in6_addr * address); +int check_is_local_address(const struct sockaddr_storage *peer, const struct sockaddr_storage *local); + int socket_set_dscp(int sockfd, uint32_t dscp, char *errbuf, size_t errbufsize); int tcp_connect(const char *hostname, int port, const char *bindaddr,