mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
lwip: Enable IPV6_ONLY option for UDP sockets (BSD & netconn)
* setsockopt(s, IPV6_ONLY, &one, sizeof(int)) will disable IPV6-only mode. Incoming/outgoing IPV4 packets are dropped. * Otherwise, sockets bound to IPV6_ANY_ADDR can receive unicast packets for IPV4 or IPV6. * sendto() a IPV6-mapped-IPV4 address on a UDP socket works correctly (not supported for RAW or TCP sockets.) * getaddrinfo() option AI_V4MAPPED is implemented. As well as extending support to TCP & RAW, there is some potential improvement to dropping incoming packets - the drop happens a bit late in the process and there is no "ICMP port unreachable" response sent.
This commit is contained in:
parent
961180617e
commit
04a2cefb26
@ -180,6 +180,16 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||
return;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/* This should be eventually moved to a flag on the UDP PCB, and this drop can happen
|
||||
more correctly in udp_input(). This will also allow icmp_dest_unreach() to be called. */
|
||||
if (conn->flags & NETCONN_FLAG_IPV6_V6ONLY && !ip_current_is_v6()) {
|
||||
LWIP_DEBUGF(API_MSG_DEBUG, ("recv_udp: Dropping IPv4 UDP packet (IPv6-only socket)"));
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
||||
if (buf == NULL) {
|
||||
pbuf_free(p);
|
||||
@ -1388,6 +1398,12 @@ lwip_netconn_do_send(void *m)
|
||||
|
||||
if (ERR_IS_FATAL(msg->conn->last_err)) {
|
||||
msg->err = msg->conn->last_err;
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
} else if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) &&
|
||||
IP_IS_V4MAPPEDV6(&msg->msg.b->addr)) {
|
||||
LWIP_DEBUGF(API_MSG_DEBUG, ("lwip_netconn_do_send: Dropping IPv4 packet on IPv6-only socket"));
|
||||
msg->err = ERR_VAL;
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
} else {
|
||||
msg->err = ERR_CONN;
|
||||
if (msg->conn->pcb.tcp != NULL) {
|
||||
|
@ -261,7 +261,7 @@ lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
* @param res pointer to a pointer where to store the result (set to NULL on failure)
|
||||
* @return 0 on success, non-zero on failure
|
||||
*
|
||||
* @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
|
||||
* @todo: implement AI_ADDRCONFIG
|
||||
*/
|
||||
int
|
||||
lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
@ -330,6 +330,9 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
type = NETCONN_DNS_IPV4;
|
||||
} else if (ai_family == AF_INET6) {
|
||||
type = NETCONN_DNS_IPV6;
|
||||
if (hints->ai_flags & AI_V4MAPPED) {
|
||||
type = NETCONN_DNS_IPV6_IPV4;
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
err = netconn_gethostbyname_addrtype(nodename, &addr, type);
|
||||
@ -346,6 +349,14 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
if (ai_family == AF_INET6 && (hints->ai_flags & AI_V4MAPPED)
|
||||
&& IP_GET_TYPE(&addr) == IPADDR_TYPE_V4) {
|
||||
/* Convert native V4 address to a V4-mapped IPV6 address */
|
||||
ip_addr_make_ip4_mapped_ip6(&addr, &addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
|
||||
if (nodename != NULL) {
|
||||
namelen = strlen(nodename);
|
||||
|
@ -2373,10 +2373,6 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
|
||||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
|
||||
/* @todo: this does not work for datagram sockets, yet */
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
|
||||
return ENOPROTOOPT;
|
||||
}
|
||||
*(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
|
||||
s, *(int *)optval));
|
||||
@ -2811,12 +2807,7 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
|
||||
case IPPROTO_IPV6:
|
||||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
/* @todo: this does not work for datagram sockets, yet */
|
||||
#if CONFIG_MDNS
|
||||
//LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
|
||||
#else
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
|
||||
#endif
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
|
||||
if (*(const int*)optval) {
|
||||
netconn_set_ipv6only(sock->conn, 1);
|
||||
} else {
|
||||
|
@ -542,6 +542,19 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
/* Unwrap IPV4-mapped IPV6 addresses and convert to native IPV4 here */
|
||||
if (IP_IS_V4MAPPEDV6(dst_ip)) {
|
||||
ip_addr_t dest_ipv4;
|
||||
ip_addr_ip4_from_mapped_ip6(&dest_ipv4, dst_ip);
|
||||
#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UP
|
||||
return udp_sendto_chksum(pcb, p, &dest_ipv4, dst_port, have_chksum, chksum);
|
||||
#else
|
||||
return udp_sendto(pcb, p, &dest_ipv4, dst_port);
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UP */
|
||||
}
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
|
||||
#if LWIP_IPV6 || (LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS)
|
||||
if (ip_addr_ismulticast(dst_ip_route)) {
|
||||
#if LWIP_IPV6
|
||||
|
@ -69,6 +69,10 @@ extern const ip_addr_t ip_addr_any_type;
|
||||
|
||||
#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6)
|
||||
#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr)))
|
||||
|
||||
#define IP_V6_EQ_PART(ipaddr, WORD, VAL) (ip_2_ip6(ipaddr)->addr[WORD] == htonl(VAL))
|
||||
#define IP_IS_V4MAPPEDV6(ipaddr) (IP_IS_V6(ipaddr) && IP_V6_EQ_PART(ipaddr, 0, 0) && IP_V6_EQ_PART(ipaddr, 1, 0) && IP_V6_EQ_PART(ipaddr, 2, 0x0000FFFF))
|
||||
|
||||
#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0)
|
||||
#define IP_SET_TYPE(ipaddr, iptype) do { if((ipaddr) != NULL) { IP_SET_TYPE_VAL(*(ipaddr), iptype); }}while(0)
|
||||
#define IP_GET_TYPE(ipaddr) ((ipaddr)->type)
|
||||
@ -156,6 +160,27 @@ extern const ip_addr_t ip_addr_any_type;
|
||||
((IP_IS_V6(addr)) ? ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen) : ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen)))
|
||||
int ipaddr_aton(const char *cp, ip_addr_t *addr);
|
||||
|
||||
/* Map an IPv4 ip_addr into an IPV6 ip_addr, using format
|
||||
defined in RFC4291 2.5.5.2.
|
||||
|
||||
Safe to call when dest==src.
|
||||
*/
|
||||
#define ip_addr_make_ip4_mapped_ip6(dest, src) do { \
|
||||
u32_t tmp = ip_2_ip4(src)->addr; \
|
||||
IP_ADDR6((dest), 0x0, 0x0, htonl(0x0000FFFF), tmp); \
|
||||
} while(0)
|
||||
|
||||
/* Convert an IPv4 mapped V6 address to an IPV4 address.
|
||||
|
||||
Check IP_IS_V4MAPPEDV6(src) before using this.
|
||||
|
||||
Safe to call when dest == src.
|
||||
*/
|
||||
#define ip_addr_ip4_from_mapped_ip6(dest, src) do { \
|
||||
ip_2_ip4(dest)->addr = ip_2_ip6(src)->addr[3]; \
|
||||
IP_SET_TYPE(dest, IPADDR_TYPE_V4); \
|
||||
} while(0)
|
||||
|
||||
#else /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
|
||||
#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb) 1
|
||||
|
Loading…
Reference in New Issue
Block a user