diff --git a/include/net/ppp.h b/include/net/ppp.h index aebb8dd7561..c5f307a4b66 100644 --- a/include/net/ppp.h +++ b/include/net/ppp.h @@ -175,6 +175,20 @@ enum ipcp_option_type { /** IP Address */ IPCP_OPTION_IP_ADDRESS = 3, + + /* RFC 1877 */ + + /** Primary DNS Server Address */ + IPCP_OPTION_DNS1 = 129, + + /** Primary NBNS Server Address */ + IPCP_OPTION_NBNS1 = 130, + + /** Secondary DNS Server Address */ + IPCP_OPTION_DNS2 = 131, + + /** Secondary NBNS Server Address */ + IPCP_OPTION_NBNS2 = 132, } __packed; /** @@ -358,6 +372,8 @@ struct lcp_options { struct ipcp_options { /** IPv4 address */ struct in_addr address; + struct in_addr dns1_address; + struct in_addr dns2_address; }; struct ipv6cp_options { diff --git a/subsys/net/l2/ppp/Kconfig b/subsys/net/l2/ppp/Kconfig index 31c8870b25d..663115ffd42 100644 --- a/subsys/net/l2/ppp/Kconfig +++ b/subsys/net/l2/ppp/Kconfig @@ -61,6 +61,12 @@ config NET_L2_PPP_OPTION_MRU_NEG help Try to negotiate with peer for MRU (MTU) for the link. +config NET_L2_PPP_OPTION_DNS_USE + bool "Use negotiated DNS servers" + depends on DNS_RESOLVER + help + Use the DNS servers negotiated in the IPCP configuration. + module = NET_L2_PPP module-dep = NET_LOG module-str = Log level for ppp L2 layer diff --git a/subsys/net/l2/ppp/ipcp.c b/subsys/net/l2/ppp/ipcp.c index 152732a2cbe..2998efcb0a6 100644 --- a/subsys/net/l2/ppp/ipcp.c +++ b/subsys/net/l2/ppp/ipcp.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Intel Corporation. + * Copyright (c) 2020 Endian Technologies AB * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +12,7 @@ LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL); #include #include +#include #include "net_private.h" @@ -37,7 +39,9 @@ static bool append_to_buf(struct net_buf *buf, u8_t *data, u8_t data_len) return true; } -/* Length is (6): code + id + IPv4 address length */ +/* Length is (6): code + id + IPv4 address length. RFC 1332 and also + * DNS in RFC 1877. + */ #define IP_ADDRESS_OPTION_LEN (1 + 1 + 4) static struct net_buf *ipcp_config_info_add(struct ppp_fsm *fsm) @@ -45,24 +49,37 @@ static struct net_buf *ipcp_config_info_add(struct ppp_fsm *fsm) struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm); - /* Currently we support only one option (IP address) */ - u8_t option[IP_ADDRESS_OPTION_LEN]; + /* Currently we support IP address and DNS servers */ + u8_t options[3 * IP_ADDRESS_OPTION_LEN]; const struct in_addr *my_addr; struct net_buf *buf; bool added; my_addr = &ctx->ipcp.my_options.address; + u8_t *option = options; option[0] = IPCP_OPTION_IP_ADDRESS; option[1] = IP_ADDRESS_OPTION_LEN; memcpy(&option[2], &my_addr->s_addr, sizeof(my_addr->s_addr)); + option += IP_ADDRESS_OPTION_LEN; + + my_addr = &ctx->ipcp.my_options.dns1_address; + option[0] = IPCP_OPTION_DNS1; + option[1] = IP_ADDRESS_OPTION_LEN; + memcpy(&option[2], &my_addr->s_addr, sizeof(my_addr->s_addr)); + + option += IP_ADDRESS_OPTION_LEN; + my_addr = &ctx->ipcp.my_options.dns2_address; + option[0] = IPCP_OPTION_DNS2; + option[1] = IP_ADDRESS_OPTION_LEN; + memcpy(&option[2], &my_addr->s_addr, sizeof(my_addr->s_addr)); buf = ppp_get_net_buf(NULL, 0); if (!buf) { goto out_of_mem; } - added = append_to_buf(buf, option, sizeof(option)); + added = append_to_buf(buf, options, sizeof(options)); if (!added) { goto out_of_mem; } @@ -184,7 +201,8 @@ static int ipcp_config_info_req(struct ppp_fsm *fsm, if (address_option_idx < 0) { /* The address option was not present, but we - * can continue without it. */ + * can continue without it. + */ NET_DBG("[%s/%p] No %saddress provided", fsm->name, fsm, "peer "); return PPP_CONFIGURE_ACK; @@ -264,6 +282,56 @@ bail_out: return -ENOMEM; } +static void ipcp_set_dns_servers(struct ppp_fsm *fsm) +{ +#if defined(CONFIG_NET_L2_PPP_OPTION_DNS_USE) + struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context, + ipcp.fsm); + + struct dns_resolve_context *dnsctx; + struct sockaddr_in dns1 = { + .sin_family = AF_INET, + .sin_port = htons(53), + .sin_addr = ctx->ipcp.my_options.dns1_address + }; + struct sockaddr_in dns2 = { + .sin_family = AF_INET, + .sin_port = htons(53), + .sin_addr = ctx->ipcp.my_options.dns2_address + }; + const struct sockaddr *dns_servers[] = { + (struct sockaddr *) &dns1, + (struct sockaddr *) &dns2, + NULL + }; + int i, ret; + + if (!dns1.sin_addr.s_addr) { + return; + } + + if (!dns2.sin_addr.s_addr) { + dns_servers[1] = NULL; + } + + dnsctx = dns_resolve_get_default(); + for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) { + if (!dnsctx->queries[i].cb) { + continue; + } + + dns_resolve_cancel(dnsctx, dnsctx->queries[i].id); + } + dns_resolve_close(dnsctx); + + ret = dns_resolve_init(dnsctx, NULL, dns_servers); + if (ret < 0) { + NET_ERR("Could not set DNS servers"); + return; + } +#endif +} + static int ipcp_config_info_nack(struct ppp_fsm *fsm, struct net_pkt *pkt, u16_t length, @@ -274,7 +342,7 @@ static int ipcp_config_info_nack(struct ppp_fsm *fsm, struct ppp_option_pkt nack_options[MAX_IPCP_OPTIONS]; enum net_verdict verdict; int i, ret, address_option_idx = -1; - struct in_addr addr; + struct in_addr addr, *dst_addr; memset(nack_options, 0, sizeof(nack_options)); @@ -304,39 +372,53 @@ static int ipcp_config_info_nack(struct ppp_fsm *fsm, case IPCP_OPTION_IP_COMP_PROTO: continue; + case IPCP_OPTION_DNS1: + dst_addr = &ctx->ipcp.my_options.dns1_address; + break; + + case IPCP_OPTION_DNS2: + dst_addr = &ctx->ipcp.my_options.dns2_address; + break; + case IPCP_OPTION_IP_ADDRESS: + dst_addr = &ctx->ipcp.my_options.address; address_option_idx = i; break; default: continue; } + + net_pkt_cursor_restore(pkt, &nack_options[i].value); + + ret = net_pkt_read(pkt, (u32_t *)&addr, sizeof(addr)); + if (ret < 0) { + /* Should not happen, is the pkt corrupt? */ + return -EMSGSIZE; + } + + memcpy(dst_addr, &addr, sizeof(addr)); + + if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) { + char dst[INET_ADDRSTRLEN]; + char *addr_str; + + addr_str = net_addr_ntop(AF_INET, &addr, dst, + sizeof(dst)); + + NET_DBG("[%s/%p] Received %s address %s", + fsm->name, fsm, + ppp_option2str(PPP_IPCP, + nack_options[i].type.ipcp), + log_strdup(addr_str)); + } } if (address_option_idx < 0) { return -EINVAL; } - net_pkt_cursor_restore(pkt, &nack_options[address_option_idx].value); - - ret = net_pkt_read(pkt, (u32_t *)&addr, sizeof(addr)); - if (ret < 0) { - /* Should not happen, is the pkt corrupt? */ - return -EMSGSIZE; - } - - memcpy(&ctx->ipcp.my_options.address, &addr, sizeof(addr)); - - if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) { - char dst[INET_ADDRSTRLEN]; - char *addr_str; - - addr_str = net_addr_ntop(AF_INET, &addr, dst, - sizeof(dst)); - - NET_DBG("[%s/%p] Received %saddress %s", - fsm->name, fsm, "", log_strdup(addr_str)); - } + ipcp_set_dns_servers(fsm); return 0; } diff --git a/subsys/net/l2/ppp/misc.c b/subsys/net/l2/ppp/misc.c index 7a27610f4a0..abcf36d1b90 100644 --- a/subsys/net/l2/ppp/misc.c +++ b/subsys/net/l2/ppp/misc.c @@ -317,6 +317,14 @@ const char *ppp_option2str(enum ppp_protocol_type protocol, return "IP_COMPRESSION_PROTOCOL"; case IPCP_OPTION_IP_ADDRESS: return "IP_ADDRESS"; + case IPCP_OPTION_DNS1: + return "DNS1"; + case IPCP_OPTION_NBNS1: + return "NBNS1"; + case IPCP_OPTION_DNS2: + return "DNS2"; + case IPCP_OPTION_NBNS2: + return "NBNS2"; } break; diff --git a/subsys/net/l2/ppp/ppp_internal.h b/subsys/net/l2/ppp/ppp_internal.h index 882624369f4..6a3780ed656 100644 --- a/subsys/net/l2/ppp/ppp_internal.h +++ b/subsys/net/l2/ppp/ppp_internal.h @@ -39,7 +39,7 @@ struct ppp_packet { #define MAX_LCP_OPTIONS CONFIG_NET_L2_PPP_MAX_OPTIONS /** Max number of IPCP options */ -#define MAX_IPCP_OPTIONS 3 +#define MAX_IPCP_OPTIONS 4 /** Max number of IPV6CP options */ #define MAX_IPV6CP_OPTIONS 1