From e240f84c75ffc583a8328b09d24cacf03991057d Mon Sep 17 00:00:00 2001 From: Flavio Santes Date: Fri, 29 Jul 2016 17:32:48 -0500 Subject: [PATCH] samples/net: DNS client application This sample code shows how to write a DNS client application. Only client functionality is implemented in this sample. The code is self-documented. Read the README file for more information about the network setup. See https://tools.ietf.org/html/rfc1035 for more information about the DNS protocol. Origin: Original Jira: ZEP-500 Jira: ZEP-501 Change-Id: Ibcfa4e392143fdc2258971304d5296d70c1c9423 Signed-off-by: Flavio Santes --- samples/net/dns_client/Makefile | 21 ++ samples/net/dns_client/README | 102 ++++++++ samples/net/dns_client/prj_galileo.conf | 17 ++ samples/net/dns_client/src/Makefile | 25 ++ samples/net/dns_client/src/app_buf.h | 19 ++ samples/net/dns_client/src/dns_pack.c | 280 ++++++++++++++++++++ samples/net/dns_client/src/dns_pack.h | 332 ++++++++++++++++++++++++ samples/net/dns_client/src/dns_utils.c | 162 ++++++++++++ samples/net/dns_client/src/dns_utils.h | 30 +++ samples/net/dns_client/src/main.c | 191 ++++++++++++++ samples/net/dns_client/src/netz.c | 223 ++++++++++++++++ samples/net/dns_client/src/netz.h | 163 ++++++++++++ samples/net/dns_client/testcase.ini | 5 + 13 files changed, 1570 insertions(+) create mode 100644 samples/net/dns_client/Makefile create mode 100644 samples/net/dns_client/README create mode 100644 samples/net/dns_client/prj_galileo.conf create mode 100644 samples/net/dns_client/src/Makefile create mode 100644 samples/net/dns_client/src/app_buf.h create mode 100644 samples/net/dns_client/src/dns_pack.c create mode 100644 samples/net/dns_client/src/dns_pack.h create mode 100644 samples/net/dns_client/src/dns_utils.c create mode 100644 samples/net/dns_client/src/dns_utils.h create mode 100644 samples/net/dns_client/src/main.c create mode 100644 samples/net/dns_client/src/netz.c create mode 100644 samples/net/dns_client/src/netz.h create mode 100644 samples/net/dns_client/testcase.ini diff --git a/samples/net/dns_client/Makefile b/samples/net/dns_client/Makefile new file mode 100644 index 00000000000..6212bb1b41e --- /dev/null +++ b/samples/net/dns_client/Makefile @@ -0,0 +1,21 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +KERNEL_TYPE = nano +BOARD = galileo +CONF_FILE = prj_galileo.conf + +include $(ZEPHYR_BASE)/Makefile.inc diff --git a/samples/net/dns_client/README b/samples/net/dns_client/README new file mode 100644 index 00000000000..f3c04e2e7a7 --- /dev/null +++ b/samples/net/dns_client/README @@ -0,0 +1,102 @@ +DNS Client Application + +Requirements +------------ + +* Ethernet LAN for testing purposes. + +* Galileo Gen 2 Development Board. + +* USB-UART cable: CH340, FTDI 6-pin or equivalent for debugging. + +* dnsmasq application. The dnsmasq version used in this sample is: + +dnsmasq -v +Dnsmasq version 2.75 Copyright (c) 2000-2015 Simon Kelley + +Building instructions +--------------------- + +* Read src/main.c, change the IP addresses according to the LAN + environment. + +* make pristine && make are enough to build this sample. + +* Follow the steps indicated here: + + https://www.zephyrproject.org/doc/board/galileo.html + + to load the binary into the Galileo Dev Board. + + +Usage +----- + +* Open a terminal window and type: + +dnsmasq -d + +* Connect the USB-UART cable to the Galileo. Open a terminal and run: + + screen /dev/ttyUSB0 115200 + +* Connect Galileo to the LAN, Turn on the board. + +* The screen terminal window will show: + + WARNING: no console will be available to OS + error: no suitable video mode found. + + ----------------------------------------- + Domain name: not_a_real_domain_name + [fiber:82] DNS Create Query: 0, ID: 1 + [fiber:85] TX: 0 + [fiber:88] RX: -5 + + ----------------------------------------- + Domain name: oops! + [fiber:82] DNS Create Query: 0, ID: 2 + [fiber:85] TX: 0 + [fiber:88] RX: 0 + [fiber:95] DNS response: 2 + + ----------------------------------------- + Domain name: zephyrproject.org + [fiber:82] DNS Create Query: 0, ID: 3 + [fiber:85] TX: 0 + [fiber:88] RX: 0 + + ****** DNS ANSWER: 0 ****** + Response: IP address Size: 4: 140 211 169 8 + [fiber:95] DNS response: 0 + + ----------------------------------------- + Domain name: www.google.com + [fiber:82] DNS Create Query: 0, ID: 4 + [fiber:85] TX: 0 + [fiber:88] RX: 0 + + ****** DNS ANSWER: 0 ****** + Response: IP address Size: 4: 216 58 192 4 + [fiber:95] DNS response: 0 + + ----------------------------------------- + Domain name: mail.yahoo.com + [fiber:82] DNS Create Query: 0, ID: 5 + [fiber:85] TX: 0 + [fiber:88] RX: 0 + + ****** DNS ANSWER: 0 ****** + Response: CNAME NO IP address Size: 8: 5 108 111 103 105 110 192 17 + CNAME: login.yahoo.com + + ****** DNS ANSWER: 1 ****** + Response: CNAME NO IP address Size: 35: 9 102 111 45 100 115 45 97 116 115 6 109 101 109 98 101 114 3 103 48 50 8 121 97 104 111 111 100 110 115 3 110 101 116 0 + CNAME: fo-ds-ats.member.g02.yahoodns.net + + ****** DNS ANSWER: 2 ****** + Response: IP address Size: 4: 98 136 189 41 + [fiber:95] DNS response: 0 + + ----------------------------------------- + Bye! diff --git a/samples/net/dns_client/prj_galileo.conf b/samples/net/dns_client/prj_galileo.conf new file mode 100644 index 00000000000..e7dd427a3fa --- /dev/null +++ b/samples/net/dns_client/prj_galileo.conf @@ -0,0 +1,17 @@ +CONFIG_STDOUT_CONSOLE=y + +CONFIG_NETWORKING=y +CONFIG_ETHERNET=y +CONFIG_ETH_DW=y + +CONFIG_NANO_TIMEOUTS=y +CONFIG_NETWORKING_WITH_TCP=y +CONFIG_NETWORKING_WITH_IPV4=y +CONFIG_NETWORKING_IPV6_NO_ND=y + +CONFIG_IP_BUF_RX_SIZE=4 +CONFIG_IP_BUF_TX_SIZE=4 + +#CONFIG_NETWORKING_WITH_LOGGING=y +#CONFIG_NETWORK_IP_STACK_DEBUG_NET_BUF=y +#CONFIG_NET_BUF_DEBUG=y diff --git a/samples/net/dns_client/src/Makefile b/samples/net/dns_client/src/Makefile new file mode 100644 index 00000000000..62e1e96d4fc --- /dev/null +++ b/samples/net/dns_client/src/Makefile @@ -0,0 +1,25 @@ +# +# Copyright (c) 2016 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ccflags-y +=-I${ZEPHYR_BASE}/net/ip/contiki +ccflags-y +=-I${ZEPHYR_BASE}/net/ip/contiki/os/lib +ccflags-y +=-I${ZEPHYR_BASE}/net/ip/contiki/os +ccflags-y +=-I${ZEPHYR_BASE}/net/ip + +obj-y += dns_pack.o +obj-y += netz.o +obj-y += dns_utils.o +obj-y += main.o diff --git a/samples/net/dns_client/src/app_buf.h b/samples/net/dns_client/src/app_buf.h new file mode 100644 index 00000000000..72706b5e3b4 --- /dev/null +++ b/samples/net/dns_client/src/app_buf.h @@ -0,0 +1,19 @@ +#ifndef _APP_BUF_H_ +#define _APP_BUF_H_ + +#include /* for __deprecated */ +#include +#include + +struct __deprecated app_buf_t; + +struct app_buf_t { + uint8_t *buf; + size_t size; + size_t length; +}; + +#define APP_BUF_INIT(_buf, _size, _length) {.buf = _buf, .size = _size,\ + .length = _length} + +#endif diff --git a/samples/net/dns_client/src/dns_pack.c b/samples/net/dns_client/src/dns_pack.c new file mode 100644 index 00000000000..bceffaf0b69 --- /dev/null +++ b/samples/net/dns_client/src/dns_pack.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dns_pack.h" + +#include + +int dns_msg_pack_qname(int *len, uint8_t *buf, int size, char *domain_name) +{ + int lb_index; + int lb_start; + int lb_size; + size_t i; + + lb_start = 0; + lb_index = 1; + lb_size = 0; + + /* traverse the domain name str, including the null-terminator :) */ + for (i = 0; i < strlen(domain_name) + 1; i++) { + if (lb_index >= size) { + return -ENOMEM; + } + + switch (domain_name[i]) { + default: + buf[lb_index] = domain_name[i]; + lb_size += 1; + break; + case '.': + buf[lb_start] = lb_size; + lb_size = 0; + lb_start = lb_index; + break; + case '\0': + buf[lb_start] = lb_size; + buf[lb_index] = 0; + break; + } + lb_index += 1; + } + + *len = lb_index; + return 0; +} + +int dns_unpack_answer(struct dns_msg_t *dns_msg, int dname_ptr) +{ + uint8_t *answer; + int buf_size; + int ptr; + + answer = dns_msg->msg + dns_msg->answer_offset; + + /* See RFC-1035 to find out why 63 */ + if (answer[0] < 63) { + return -ENOMEM; + } + + /* Recovery of the pointer value */ + ptr = (((answer[0] & 63) << 8) + answer[1]); + if (ptr != dname_ptr) { + return -ENOMEM; + } + + /* + * We need to be sure this buffer has enough space + * to parse the answer. + * + * size: dname_size + type + class + ttl + rdlength + rdata + * 2 + 2 + 2 + 4 + 2 + ? + * + * So, answer size >= 12 + * + * See RFC-1035 4.1.3. Resource record format + */ + buf_size = dns_msg->msg_size - dns_msg->answer_offset; + if (buf_size < 12) { + return -ENOMEM; + } + + /* Only answers of type Internet. + * Here we use 2 as an offset because a ptr uses only 2 bytes. + */ + if (dns_answer_class(2, answer) != DNS_CLASS_IN) { + return -EINVAL; + } + + switch (dns_response_type(2, answer)) { + case DNS_RR_TYPE_A: + case DNS_RR_TYPE_AAAA: + dns_msg->response_type = DNS_RESPONSE_IP; + dns_msg->response_position = dns_msg->answer_offset + 12; + dns_msg->response_length = dns_answer_rdlength(2, answer); + + return 0; + + case DNS_RR_TYPE_CNAME: + + dns_msg->response_type = DNS_RESPONSE_CNAME_NO_IP; + dns_msg->response_position = dns_msg->answer_offset + 12; + dns_msg->response_length = dns_answer_rdlength(2, answer); + + return 0; + + default: + /* malformed dns answer */ + return -EINVAL; + } + + return 0; +} + +int dns_unpack_response_header(struct dns_msg_t *msg, int src_id) +{ + uint8_t *dns_header; + int size; + int qdcount; + int ancount; + + dns_header = msg->msg; + size = msg->msg_size; + + if (size < DNS_MSG_HEADER_SIZE) { + return -ENOMEM; + } + + if (dns_header_id(dns_header) != src_id) { + return -EINVAL; + } + + if (dns_header_qr(dns_header) != DNS_RESPONSE) { + return -EINVAL; + } + + if (dns_header_opcode(dns_header) != DNS_QUERY) { + return -EINVAL; + } + + if (dns_header_z(dns_header) != 0) { + return -EINVAL; + } + + switch (dns_header_rcode(dns_header)) { + case DNS_HEADER_NOERROR: + break; + default: + return dns_header_rcode(dns_header); + + } + + qdcount = dns_header_qdcount(dns_header); + ancount = dns_header_ancount(dns_header); + if (qdcount < 1 || ancount < 1) { + return -EINVAL; + } + + return 0; +} + +static int dns_msg_pack_query_header(uint8_t *buf, int size, uint16_t id) +{ + if (size < DNS_MSG_HEADER_SIZE) { + return -ENOMEM; + } + + *(uint16_t *)(buf + 0) = z_swap2(id); + + /* RD = 1, TC = 0, AA = 0, Opcode = 0, QR = 0 <-> 0x01 (1B) + * RCode = 0, Z = 0, RA = 0 <-> 0x00 (1B) + * + * QDCOUNT = 1 <-> 0x0001 (2B) + */ + + *(uint32_t *)(buf + 2) = 0x01000001; + *(uint32_t *)(buf + 6) = 0; + *(uint16_t *)(buf + 10) = 0; + + return 0; +} + +int dns_msg_pack_query(struct app_buf_t *buf, char *domain_name, + uint16_t id, enum dns_rr_type qtype) +{ + int qname_len; + int offset; + int rc; + + rc = dns_msg_pack_query_header(buf->buf, buf->size, id); + if (rc != 0) { + return rc; + } + + offset = DNS_MSG_HEADER_SIZE; + + rc = dns_msg_pack_qname(&qname_len, buf->buf + offset, + buf->size - offset, domain_name); + if (rc != 0) { + return rc; + } + + offset += qname_len; + + /* 4Bytes required: QType: (2B), QClass (2B) */ + if (offset + 4 > buf->size) { + return rc; + } + /* QType */ + *(uint16_t *)(buf->buf + offset + 0) = z_swap2(qtype); + /* QClass */ + *(uint16_t *)(buf->buf + offset + 2) = z_swap2(DNS_CLASS_IN); + + buf->length = offset + 4; + + return 0; +} + +int dns_find_null(int *qname_size, uint8_t *buf, int size) +{ + *qname_size = 0; + while (*qname_size < size) { + if (buf[(*qname_size)++] == 0x00) { + return 0; + } + } + + return -ENOMEM; +} + +int dns_unpack_response_query(struct dns_msg_t *dns_msg) +{ + uint8_t *dns_query; + int remaining_size; + int qname_size; + int offset; + int rc; + + dns_msg->query_offset = DNS_MSG_HEADER_SIZE; + dns_query = dns_msg->msg + dns_msg->query_offset; + remaining_size = dns_msg->msg_size - dns_msg->query_offset; + + rc = dns_find_null(&qname_size, dns_query, remaining_size); + if (rc != 0) { + return rc; + } + + /* header already parsed + qname size */ + offset = dns_msg->query_offset + qname_size; + /* 4 bytes more for qtype and qclass */ + offset += 4; + if (offset > dns_msg->msg_size) { + return -ENOMEM; + } + + if (dns_query_qtype(dns_query + qname_size) != DNS_RR_TYPE_A && + dns_query_qtype(dns_query + qname_size) != DNS_RR_TYPE_AAAA) { + return -EINVAL; + } + + if (dns_query_qclass(dns_query + qname_size) != DNS_CLASS_IN) { + return -EINVAL; + } + + dns_msg->answer_offset = dns_msg->query_offset + qname_size + 4; + + return 0; +} diff --git a/samples/net/dns_client/src/dns_pack.h b/samples/net/dns_client/src/dns_pack.h new file mode 100644 index 00000000000..67b74f33900 --- /dev/null +++ b/samples/net/dns_client/src/dns_pack.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _DNS_PACK_H_ +#define _DNS_PACK_H_ + +#include +#include +#include + +#include + +/** + * @brief dns_msg_t + * + * @details Structure that points to the buffer containing the + * DNS message. It also contains some decodified + * message's properties that can not be recovered easily: + * + * - cname_offset + * + * - query_offset + * + * - answer_offset: + * + * - response_type + * It indicates the response's content type. It could be + * an IP address, a CNAME with IP (two answers), a CNAME + * with no IP address. See enum dns_response_type for + * more details. + * + * - response_position: this is an offset. It holds the + * starting byte of the field containing the desired + * info. For example an IPv4 address. + * + * - response_length: this is an offset. It holds the + * response's length. + */ +struct dns_msg_t { + uint8_t *msg; + size_t msg_size; + + int response_type; + int response_position; + int response_length; + + int cname_offset; + int query_offset; + int answer_offset; +}; + +#define DNS_MSG_INIT(b, s) {.msg = b, .msg_size = s, \ + .response_type = -EINVAL} + + +enum dns_rr_type { + DNS_RR_TYPE_INVALID = 0, + DNS_RR_TYPE_A = 1, /* IPv4 */ + DNS_RR_TYPE_CNAME = 5, /* CNAME */ + DNS_RR_TYPE_AAAA = 28 /* IPv6 */ +}; + +enum dns_response_type { + DNS_RESPONSE_INVALID = -EINVAL, + DNS_RESPONSE_IP, + DNS_RESPONSE_CNAME_WITH_IP, + DNS_RESPONSE_CNAME_NO_IP +}; + +enum dns_class { + DNS_CLASS_INVALID = 0, + DNS_CLASS_IN, +}; + +enum dns_msg_type { + DNS_QUERY = 0, + DNS_RESPONSE +}; + +enum dns_header_rcode { + DNS_HEADER_NOERROR = 0, + DNS_HEADER_FORMATERROR, + DNS_HEADER_SERVERFAILURE, + DNS_HEADER_NAMEERROR, + DNS_HEADER_NOTIMPLEMENTED, + DNS_HEADER_REFUSED +}; + +/* See 4.1.1 Header section format + * DNS Message Header is always 12 bytes + */ +#define DNS_MSG_HEADER_SIZE 12 + +static inline uint32_t z_swap4(uint32_t n) +{ + return ((n&0x000000FF)<<24) + ((n&0x0000FF00)<<8) + + ((n&0x00FF0000)>>8) + ((n&0xFF000000)>>24); +} + +static inline uint16_t z_swap2(uint16_t n) +{ + return (n>>8) + ((n & 0x00FF) << 8); +} + + +/** It returns the ID field in the DNS msg header */ +static inline int dns_header_id(uint8_t *header) +{ + return z_swap2(*(uint16_t *)header); +} + +/** It returns the QR field in the DNS msg header */ +static inline int dns_header_qr(uint8_t *header) +{ + return ((*(header + 2)) & 0x80) ? 1 : 0; +} + +/** It returns the OPCODE field in the DNS msg header */ +static inline int dns_header_opcode(uint8_t *header) +{ + return ((*(header + 2)) & 0x70) >> 1; +} + +/** It returns the AA field in the DNS msg header */ +static inline int dns_header_aa(uint8_t *header) +{ + return ((*(header + 2)) & 0x04) ? 1 : 0; +} + +/** It returns the TC field in the DNS msg header */ +static inline int dns_header_tc(uint8_t *header) +{ + return ((*(header + 2)) & 0x02) ? 1 : 0; +} + +/** It returns the RD field in the DNS msg header */ +static inline int dns_header_rd(uint8_t *header) +{ + return ((*(header + 2)) & 0x01) ? 1 : 0; +} + +/** It returns the RA field in the DNS msg header */ +static inline int dns_header_ra(uint8_t *header) +{ + return ((*(header + 3)) & 0x80) >> 7; +} + +/** It returns the Z field in the DNS msg header */ +static inline int dns_header_z(uint8_t *header) +{ + return ((*(header + 3)) & 0x70) >> 4; +} + +/** It returns the RCODE field in the DNS msg header */ +static inline int dns_header_rcode(uint8_t *header) +{ + return ((*(header + 3)) & 0x0F); +} + +/** It returns the QDCOUNT field in the DNS msg header */ +static inline int dns_header_qdcount(uint8_t *header) +{ + return z_swap2(*(uint16_t *)(header + 4)); +} + +/** It returns the ANCOUNT field in the DNS msg header */ +static inline int dns_header_ancount(uint8_t *header) +{ + return z_swap2(*(uint16_t *)(header + 6)); +} + +/** It returns the NSCOUNT field in the DNS msg header */ +static inline int dns_header_nscount(uint8_t *header) +{ + return z_swap2(*(uint16_t *)(header + 8)); +} + +/** It returns the ARCOUNT field in the DNS msg header */ +static inline int dns_header_arcount(uint8_t *header) +{ + return z_swap2(*(uint16_t *)(header + 10)); +} + +static inline int dns_query_qtype(uint8_t *question) +{ + return z_swap2(*((uint16_t *)(question + 0))); +} + +static inline int dns_query_qclass(uint8_t *question) +{ + return z_swap2(*((uint16_t *)(question + 2))); +} + +static inline int dns_response_type(int dname_size, uint8_t *answer) +{ + /** Future versions must consider byte 0 + * *(answer + dname_size + 0); + */ + return *(answer + dname_size + 1); +} + +static inline int dns_answer_class(int dname_size, uint8_t *answer) +{ + /** Future versions must consider byte 2 + * *(answer + dname_size + 2); + */ + return *(answer + dname_size + 3); +} + +static inline int dns_answer_ttl(int dname_size, uint8_t *answer) +{ + return z_swap4(*(uint32_t *)(answer + dname_size + 4)); +} + +static inline int dns_answer_rdlength(int dname_size, uint8_t *answer) +{ + return z_swap2(*(uint16_t *)(answer + dname_size + 8)); +} + +/** + * @brief dns_msg_pack_qname Packs a QNAME + * @param len Bytes used by this function + * @param buf Buffer + * @param sizeof Buffer's size + * @param domain_name Something like www.example.com + * @return 0 on success + * @return -ENOMEM if there is no enough space to store + * the resultant QNAME + */ +int dns_msg_pack_qname(int *len, uint8_t *buf, int size, char *domain_name); + + +/** + * @brief dns_unpack_answer Unpacks an answer message + * @param dns_msg Structure + * @param dname_ptr An index to the previous CNAME. For example + * for the first answer, ptr must be 0x0c, the + * DNAME at the question. + * @return 0 on success + * @return -ENOMEM on error + */ +int dns_unpack_answer(struct dns_msg_t *dns_msg, int dname_ptr); + +/** + * @brief dns_unpack_response_header + * + * @details Unpacks the header's response. + * + * @param msg Structure containing the response. + * + * @param src_id Transaction id, it must match the id + * used in the query datagram sent to the + * DNS server. + * @return 0 on success + * + * @return -ENOMEM if the buffer in msg has no + * enough space to store the header. + * The header is always 12 bytes length. + * + * @return -EINVAL: + * * if the src_id does not match the + * header's id. + * * if the header's QR value is + * not DNS_RESPONSE. + * * if the header's OPCODE value is not + * DNS_QUERY. + * * if the header's Z value is not 0. + * * if the question counter is not 1 or + * the answer counter is less than 1. + * + * RFC 1035 RCODEs (> 0): + * + * 1 Format error + * 2 Server failure + * 3 Name Error + * 4 Not Implemented + * 5 Refused + * + */ +int dns_unpack_response_header(struct dns_msg_t *msg, int src_id); + +/** + * @brief dns_msg_pack_query Packs the query message + * @param buf Buffer that will contain the resultant query + * @param domain_name Something like: www.example.com + * @param id Transaction Identifier + * @param qtype Query type: AA, AAAA. See enum dns_rr_type + * @return 0 on success + * @return On error, a negative value is returned. See: + * - dns_msg_pack_query_header + * - dns_msg_pack_qname + */ +int dns_msg_pack_query(struct app_buf_t *buf, char *domain_name, + uint16_t id, enum dns_rr_type qtype); + +/** + * @brief dns_unpack_response_query + * + * @details Unpacks the response's query. RFC 1035 states that the + * response's query comes after the first 12 bytes, + * i.e. afther the message's header. + * + * This function computes the answer_offset field. + * + * @param dns_msg Structure containing the message. + * + * @return 0 on success + * @return -ENOMEM: + * * if the null label is not found after + * traversing the buffer. + * * if QCLASS and QTYPE are not found. + * @return -EINVAL: + * * if QTYPE is not "A" (IPv4) or "AAAA" (IPv6). + * * if QCLASS is not "IN". + * + */ +int dns_unpack_response_query(struct dns_msg_t *dns_msg); + +#endif diff --git a/samples/net/dns_client/src/dns_utils.c b/samples/net/dns_client/src/dns_utils.c new file mode 100644 index 00000000000..7ebccdcaa22 --- /dev/null +++ b/samples/net/dns_client/src/dns_utils.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dns_pack.h" + +#include +#include + +int dns_print_msg_header(uint8_t *header, int size) +{ + if (size < DNS_MSG_HEADER_SIZE) { + return -ENOMEM; + } + + printf("\nHeader\n"); + printf("\tFlags\n"); + printf("\t\tTransaction ID:\t\t%d\n", dns_header_id(header)); + printf("\t\tMessage type:\t\t%d (%s)\n", dns_header_qr(header), + (dns_header_qr(header) == DNS_QUERY ? "query" : "response")); + printf("\t\tOperation code:\t\t%d (%s)\n", dns_header_opcode(header), + (dns_header_opcode(header) == DNS_QUERY ? "query" : "other")); + printf("\t\tAuthoritative:\t\t%d (%s)\n", dns_header_aa(header), + (dns_header_aa(header) ? "true" : "false")); + printf("\t\tTruncated:\t\t%d (%s)\n", dns_header_tc(header), + (dns_header_tc(header) ? "true" : "false")); + printf("\t\tRecursion desired:\t%d (%s)\n", dns_header_rd(header), + (dns_header_rd(header) ? "true" : "false")); + printf("\t\tRecursion avaialable:\t%d (%s)\n", dns_header_ra(header), + (dns_header_ra(header) ? "true" : "false")); + printf("\t\tZ:\t\t\t%d\n", dns_header_z(header)); + printf("\t\tResponse code:\t\t%d (%s)\n", dns_header_rcode(header), + (dns_header_rcode(header) == 0 ? "no error" : "error")); + printf("\tQuestion counter:\t%d\n", dns_header_qdcount(header)); + printf("\tAnswer counter:\t\t%d\n", dns_header_ancount(header)); + printf("\tNServer counter:\t%d\n", dns_header_nscount(header)); + printf("\tAdditional counter:\t%d\n", dns_header_arcount(header)); + + return 0; +} + +int dns_print_label(uint8_t *label, int size) +{ + int n; + int i; + + i = 0; + while (i < size) { + n = label[i]; + if (n == 0) { + break; + } else if (n > 63) { + break; + } else if (i + n <= size) { + + if (i) { + printf("."); + } + int j = i + 1; /* next char */ + + while (j < i + 1 + n) { + printf("%c", label[j]); + j++; + } + + i += n + 1; /* content + octect size */ + } else { + i = 0; /* no memory! */ + break; + } + } + + if (i == 0) { + return -ENOMEM; + } + + return 0; +} + +int dns_print_msg_query(uint8_t *qname, int qname_size, int qtype, int qclass) +{ + printf("\nQuery\n"); + printf("\tQuery name\n\t\tLabel size:\t%d\n\t\tDomain name:\t", + qname_size); + dns_print_label(qname, qname_size); + printf("\n"); + printf("\tQuery type:\t\t%d\n", qtype); + printf("\tQuery class:\t\t%d\n", qclass); + + return 0; +} + +int dns_print_readable_msg_label(int offset, uint8_t *buf, int size) +{ + int next; + int i; + int j; + + for (i = offset; i < size;) { + if (buf[i] <= 63) { + /* +1 because the null label or a pointer */ + if (i + buf[i] + 1 >= size) { + return -ENOMEM; + } + + for (j = 1; j <= buf[i]; j++) { + printf("%c", buf[i + j]); + } + i += buf[i] + 1; + if (buf[i] == 0) { + break; + } + printf("."); + + } else { + if (i + 1 >= size) { + return -ENOMEM; + } + + next = ((buf[i] & 0x3F) << 8) + buf[i + 1]; + if (next >= size) { + return -ENOMEM; + } + i = next; + offset = next; + } + } + printf("\n"); + + return 0; +} + +int print_buf(uint8_t *buf, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) { + printf("%d ", buf[i]); + } + printf("\n"); + + return 0; +} + + +int print_app_buf(struct app_buf_t *buf) +{ + print_buf(buf->buf, buf->length); + return 0; +} diff --git a/samples/net/dns_client/src/dns_utils.h b/samples/net/dns_client/src/dns_utils.h new file mode 100644 index 00000000000..934e1978e00 --- /dev/null +++ b/samples/net/dns_client/src/dns_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _DNS_UTILS_H_ +#define _DNS_UTILS_H_ + +#include +#include + +int dns_print_msg_header(uint8_t *header, int size); +int dns_print_msg_query(uint8_t *qname, int qname_size, int qtype, int qclass); +int dns_print_label(uint8_t *label, int size); +int dns_print_readable_msg_label(int offset, uint8_t *buf, int size); +int print_buf(uint8_t *buf, size_t size); +int print_app_buf(struct app_buf_t *buf); + +#endif diff --git a/samples/net/dns_client/src/main.c b/samples/net/dns_client/src/main.c new file mode 100644 index 00000000000..b7e14f64f62 --- /dev/null +++ b/samples/net/dns_client/src/main.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "dns_pack.h" +#include "dns_utils.h" +#include "netz.h" + +#define STACK_SIZE 1024 +uint8_t stack[STACK_SIZE]; + +#define BUF_SIZE 1024 + +uint8_t tx_raw_buf[BUF_SIZE]; +uint8_t rx_raw_buf[BUF_SIZE]; + +#define SLEEP_TIME 10 + +char *domains[] = {"not_a_real_domain_name", "oops!", + "zephyrproject.org", "www.google.com", + "mail.yahoo.com", NULL}; + +int dns_query(struct app_buf_t *buf, char *str, uint16_t id, + enum dns_rr_type qtype); + +int dns_response(struct app_buf_t *_buf, int *response_type, int src_id); + +void fiber(void) +{ + struct app_buf_t tx_buf = APP_BUF_INIT(tx_raw_buf, + sizeof(tx_raw_buf), 0); + + struct app_buf_t rx_buf = APP_BUF_INIT(rx_raw_buf, + sizeof(rx_raw_buf), 0); + + struct netz_ctx_t netz_ctx = NETZ_CTX_INIT; + + int response_type; + int counter; + char *name; + int rc; + + netz_host_ipv4(&netz_ctx, 192, 168, 1, 101); + netz_remote_ipv4(&netz_ctx, 192, 168, 1, 10, 5353); + netz_netmask_ipv4(&netz_ctx, 255, 255, 255, 0); + netz_udp(&netz_ctx); + + counter = 0; + do { + fiber_sleep(300); + + printf("\n-----------------------------------------\n"); + + name = domains[counter]; + if (name == NULL) { + counter = 0; + break; + } + counter += 1; + + printf("Domain name: %s\n", name); + + rc = dns_query(&tx_buf, name, counter, DNS_RR_TYPE_A); + printf("[%s:%d] DNS Create Query: %d, ID: %d\n", + __func__, __LINE__, rc, counter); + + rc = netz_tx(&netz_ctx, &tx_buf); + printf("[%s:%d] TX: %d\n", __func__, __LINE__, rc); + + rc = netz_rx(&netz_ctx, &rx_buf); + printf("[%s:%d] RX: %d\n", __func__, __LINE__, rc); + + if (rc != 0) { + continue; + } + + rc = dns_response(&rx_buf, &response_type, counter); + printf("[%s:%d] DNS response: %d\n", __func__, __LINE__, rc); + + + } while (1); + + printf("Bye!\n"); + +} + +void main(void) +{ + net_init(); + + task_fiber_start(stack, STACK_SIZE, (nano_fiber_entry_t)fiber, + 0, 0, 7, 0); +} + + +int dns_query(struct app_buf_t *buf, char *str, uint16_t id, + enum dns_rr_type qtype) +{ + return dns_msg_pack_query(buf, str, id, qtype); +} + +int dns_response(struct app_buf_t *_buf, int *response_type, int src_id) +{ + struct dns_msg_t dns_msg = DNS_MSG_INIT(_buf->buf, _buf->size); + int ptr; + int rc; + int i; + + rc = dns_unpack_response_header(&dns_msg, src_id); + if (rc != 0) { + return rc; + } + + if (dns_header_qdcount(dns_msg.msg) != 1) { + return -EINVAL; + } + + rc = dns_unpack_response_query(&dns_msg); + if (rc != 0) { + return rc; + } + + i = 0; + /* the first dname is at 0x0c bytes */ + ptr = 0x0c; + while (i < dns_header_ancount(dns_msg.msg)) { + + printf("\n****** DNS ANSWER: %d ******\n", i); + + rc = dns_unpack_answer(&dns_msg, ptr); + if (rc != 0) { + printf("[%s:%d]\n", __func__, __LINE__); + return rc; + } + + switch (dns_msg.response_type) { + case DNS_RESPONSE_IP: + printf("Response: IP address\t\tSize: %d:\t", + dns_msg.response_length); + print_buf(dns_msg.msg + dns_msg.response_position, + dns_msg.response_length); + break; + + case DNS_RESPONSE_CNAME_NO_IP: + printf("Response: CNAME NO IP address\t\tSize: %d:\t", + dns_msg.response_length); + print_buf(dns_msg.msg + dns_msg.response_position, + dns_msg.response_length); + printf("CNAME: "); + dns_print_readable_msg_label(dns_msg.response_position, + dns_msg.msg, + dns_msg.msg_size); + + ptr = dns_msg.response_position; + + break; + + case DNS_RESPONSE_CNAME_WITH_IP: + printf("Response: CNAME WITH IP addr\t\tSize: %d:\t", + dns_msg.response_length); + break; + } + + dns_msg.answer_offset = dns_msg.answer_offset + 12 + + dns_msg.response_length; + + + ++i; + } + + *response_type = dns_msg.response_type; + + return 0; +} diff --git a/samples/net/dns_client/src/netz.c b/samples/net/dns_client/src/netz.c new file mode 100644 index 00000000000..329a92f18e5 --- /dev/null +++ b/samples/net/dns_client/src/netz.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include +#include + +void netz_host(struct netz_ctx_t *ctx, struct net_addr *host) +{ + return netz_host_ipv4(ctx, host->in_addr.in4_u.u4_addr8[0], + host->in_addr.in4_u.u4_addr8[1], + host->in_addr.in4_u.u4_addr8[2], + host->in_addr.in4_u.u4_addr8[3]); +} + +void netz_host_ipv4(struct netz_ctx_t *ctx, uint8_t a1, uint8_t a2, + uint8_t a3, uint8_t a4) +{ + uip_ipaddr_t host_addr; + + uip_ipaddr(&host_addr, a1, a2, a3, a4); + uip_sethostaddr(&host_addr); + + ctx->host.in_addr.in4_u.u4_addr8[0] = a1; + ctx->host.in_addr.in4_u.u4_addr8[1] = a2; + ctx->host.in_addr.in4_u.u4_addr8[2] = a3; + ctx->host.in_addr.in4_u.u4_addr8[3] = a4; + ctx->host.family = AF_INET; +} + +void netz_netmask(struct netz_ctx_t *ctx, struct net_addr *netmask) +{ + return netz_netmask_ipv4(ctx, netmask->in_addr.in4_u.u4_addr8[0], + netmask->in_addr.in4_u.u4_addr8[1], + netmask->in_addr.in4_u.u4_addr8[2], + netmask->in_addr.in4_u.u4_addr8[3]); +} + +void netz_netmask_ipv4(struct netz_ctx_t *ctx, uint8_t n1, uint8_t n2, + uint8_t n3, uint8_t n4) +{ + ARG_UNUSED(ctx); + + uip_ipaddr_t netmask; + + uip_ipaddr(&netmask, n1, n2, n3, n4); + uip_setnetmask(&netmask); +} + +void netz_remote(struct netz_ctx_t *ctx, struct net_addr *remote, int port) +{ + return netz_remote_ipv4(ctx, remote->in_addr.in4_u.u4_addr8[0], + remote->in_addr.in4_u.u4_addr8[1], + remote->in_addr.in4_u.u4_addr8[2], + remote->in_addr.in4_u.u4_addr8[3], port); +} + +void netz_remote_ipv4(struct netz_ctx_t *ctx, uint8_t a1, uint8_t a2, + uint8_t a3, uint8_t a4, int port) +{ + ctx->remote.in_addr.in4_u.u4_addr8[0] = a1; + ctx->remote.in_addr.in4_u.u4_addr8[1] = a2; + ctx->remote.in_addr.in4_u.u4_addr8[2] = a3; + ctx->remote.in_addr.in4_u.u4_addr8[3] = a4; + ctx->remote.family = AF_INET; + + ctx->remote_port = port; +} + +static int netz_prepare(struct netz_ctx_t *ctx, enum ip_protocol proto) +{ +#ifdef CONFIG_NETWORKING_WITH_TCP + struct app_buf_t buf = APP_BUF_INIT(NULL, 0, 0); + int rc; +#endif + + ctx->connected = 0; + ctx->proto = proto; + + ctx->net_ctx = net_context_get(ctx->proto, + &ctx->remote, ctx->remote_port, + &ctx->host, 0); + if (ctx->net_ctx == NULL) { + return -EINVAL; + } + +#ifdef CONFIG_NETWORKING_WITH_TCP + /* workaround to activate the IP stack */ + rc = netz_tx(ctx, &buf); + if (rc != 0) { + return rc; + } +#endif + ctx->connected = 1; + return 0; +} + +int netz_tcp(struct netz_ctx_t *ctx) +{ + return netz_prepare(ctx, IPPROTO_TCP); +} + +int netz_udp(struct netz_ctx_t *ctx) +{ + return netz_prepare(ctx, IPPROTO_UDP); +} + +static void netz_sleep(int sleep_ticks) +{ + struct nano_timer timer; + + nano_timer_init(&timer, NULL); + nano_fiber_timer_start(&timer, sleep_ticks); + nano_fiber_timer_test(&timer, TICKS_UNLIMITED); +} + +static int tcp_tx(struct net_context *ctx, uint8_t *buf, size_t size, + int tx_retry_timeout) +{ + struct net_buf *nbuf; + uint8_t *ptr; + int rc; + + nbuf = ip_buf_get_tx(ctx); + if (nbuf == NULL) { + return -EINVAL; + } + + ptr = net_buf_add(nbuf, size); + memcpy(ptr, buf, size); + ip_buf_appdatalen(nbuf) = size; + + do { + rc = net_send(nbuf); + + if (rc >= 0) { + ip_buf_unref(nbuf); + return 0; + } + switch (rc) { + case -EINPROGRESS: + netz_sleep(tx_retry_timeout); + break; + case -EAGAIN: + case -ECONNRESET: + netz_sleep(tx_retry_timeout); + break; + default: + ip_buf_unref(nbuf); + return -EIO; + } + } while (1); + + return 0; +} + +static int tcp_rx(struct net_context *ctx, uint8_t *buf, size_t *read_bytes, + size_t size, int rx_timeout) +{ + struct net_buf *nbuf; + int rc; + + nbuf = net_receive(ctx, rx_timeout); + if (nbuf == NULL) { + return -EIO; + } + + *read_bytes = ip_buf_appdatalen(nbuf); + if (*read_bytes > size) { + *read_bytes = size; + rc = -ENOMEM; + } else { + rc = 0; + } + + memcpy(buf, ip_buf_appdata(nbuf), *read_bytes); + ip_buf_unref(nbuf); + + return rc; +} + +int netz_tx(struct netz_ctx_t *ctx, struct app_buf_t *buf) +{ + int rc; + + /* We don't evaluate if we are connected. */ + + rc = tcp_tx(ctx->net_ctx, buf->buf, buf->length, + ctx->tx_retry_timeout); + + return rc; +} + +int netz_rx(struct netz_ctx_t *ctx, struct app_buf_t *buf) +{ + int rc; + + if (ctx->connected != 1) { + return -ENOTCONN; + } + + rc = tcp_rx(ctx->net_ctx, buf->buf, &buf->length, buf->size, + ctx->rx_timeout); + + return rc; +} diff --git a/samples/net/dns_client/src/netz.h b/samples/net/dns_client/src/netz.h new file mode 100644 index 00000000000..3830b9a56a3 --- /dev/null +++ b/samples/net/dns_client/src/netz.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _NETZ_H_ +#define _NETZ_H_ + +#include +#include + +#include "app_buf.h" + +struct __deprecated netz_ctx_t; + +struct netz_ctx_t { + struct net_context *net_ctx; + int connected; + + int rx_timeout; + int tx_retry_timeout; + + struct net_addr host; + int host_port; + + struct net_addr remote; + int remote_port; + + enum ip_protocol proto; +}; + +#define TCP_COMMON_TIMEOUT 20 + +/** + * @brief NETZ_CTX_INIT Initializes a netz context with default values + */ +#define NETZ_CTX_INIT { .rx_timeout = TCP_COMMON_TIMEOUT, \ + .tx_retry_timeout = TCP_COMMON_TIMEOUT, \ + .net_ctx = NULL, \ + .connected = 0, \ + .proto = IPPROTO_UDP, \ + .host_port = 0, \ + .remote_port = 0} + +/** + * @brief NET_ADDR_IPV4_INIT Initializes a net_addr structure with + * an IPv4 address specified by a1, a2, a3 and a4 + */ +#define NET_ADDR_IPV4_INIT(a1, a2, a3, a4) {.in_addr.in4_u.u4_addr8[0] = (a1),\ + .in_addr.in4_u.u4_addr8[1] = (a2),\ + .in_addr.in4_u.u4_addr8[2] = (a3),\ + .in_addr.in4_u.u4_addr8[3] = (a4),\ + .family = AF_INET} + +/** + * @brief netz_host Sets the host IPv4 address (no IPv6 support) + * @param ctx netz context structure + * @param host Network address + */ +void __deprecated netz_host(struct netz_ctx_t *ctx, struct net_addr *host); + +/** + * @brief netz_host_ipv4 Sets the host IPv4 address (no IPv6 support) + * @param ctx netz context structure + * @param a1 Byte 0 of the IPv4 address + * @param a2 Byte 1 of the IPv4 address + * @param a3 Byte 2 of the IPv4 address + * @param a4 Byte 3 of the IPv4 address + */ +void __deprecated netz_host_ipv4(struct netz_ctx_t *ctx, uint8_t a1, + uint8_t a2, uint8_t a3, uint8_t a4); + +/** + * @brief netz_netmask Sets the host's netmask address + * @param ctx netz context structure + * @param netmask Network address to be used as netmask + */ +void __deprecated netz_netmask(struct netz_ctx_t *ctx, + struct net_addr *netmask); + +/** + * @brief netz_netmask_ipv4 Sets the host's netmask IPv4 address + * @param ctx netz context structure + * @param n1 Byte 0 of the IPv4 address + * @param n2 Byte 1 of the IPv4 address + * @param n3 Byte 2 of the IPv4 address + * @param n4 Byte 3 of the IPv4 address + */ +void __deprecated netz_netmask_ipv4(struct netz_ctx_t *ctx, uint8_t n1, + uint8_t n2, uint8_t n3, uint8_t n4); +/** + * @brief netz_remote Sets the address of the remote peer + * @param ctx netz context structure + * @param remote Network address of the remote peer + * @param port Port number of the remote peer + */ +void __deprecated netz_remote(struct netz_ctx_t *ctx, struct net_addr *remote, + int port); + +/** + * @brief netz_remote_ipv4 Sets the IPv4 address of the remote peer + * @param ctx netz context structure + * @param a1 Byte 0 of the IPv4 address + * @param a2 Byte 1 of the IPv4 address + * @param a3 Byte 2 of the IPv4 address + * @param a4 Byte 3 of the IPv4 address + */ + +void __deprecated netz_remote_ipv4(struct netz_ctx_t *ctx, uint8_t a1, + uint8_t a2, uint8_t a3, uint8_t a4, + int port); + +/** + * @brief netz_tcp Initializes the netz context & connects + * to the remote peer + * @param ctx netz context structure + * @return 0 on success + * @return -EINVAL if a null context was obtained + * @return Read netz_tx return codes + */ +int __deprecated netz_tcp(struct netz_ctx_t *ctx); + +/** + * @brief netz_udp Initializes the context for UDP transfers + * @param ctx netz context structure + * @return 0 on success + * @return -EINVAL if a null context was obtained + */ +int __deprecated netz_udp(struct netz_ctx_t *ctx); + +/** + * @brief netz_tx TCP/UDP data transmission + * @param ctx netz context structure + * @param buf Buffer that contains the data to be sent + * @return 0 on success + * @return -EINVAL if no network buffer is available + * @return -EIO if a TCP error was detected + */ +int __deprecated netz_tx(struct netz_ctx_t *ctx, struct app_buf_t *buf); + +/** + * @brief netz_rx TCP/UDP data reception + * @param ctx netz context structure + * @param buf Buffer that contains the received data + * @return 0 on success + * @return -EIO on TCP or network buffer error + * @return -ENOMEM if the space in buf is not enough + * to store the received data + */ +int __deprecated netz_rx(struct netz_ctx_t *ctx, struct app_buf_t *buf); + +#endif diff --git a/samples/net/dns_client/testcase.ini b/samples/net/dns_client/testcase.ini new file mode 100644 index 00000000000..99297a6174e --- /dev/null +++ b/samples/net/dns_client/testcase.ini @@ -0,0 +1,5 @@ +[test] +tags = net +build_only = true +arch_whitelist = x86 +platform_whitelist = galileo