mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
MDNS-Fuzzer: AFL fuzzer tests for mdsn packet parser
This commit is contained in:
parent
b827e0e331
commit
e983230be9
@ -18,12 +18,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MDNS_TEST_MODE
|
||||
#include <tcpip_adapter.h>
|
||||
#include "esp_event.h"
|
||||
#else
|
||||
#include "esp32_compat.h"
|
||||
#endif
|
||||
|
||||
#define MDNS_TYPE_A 0x0001
|
||||
#define MDNS_TYPE_PTR 0x000C
|
||||
|
@ -11,25 +11,11 @@
|
||||
// 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 "mdns.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_event_loop.h"
|
||||
|
||||
#include "mdns_private.h"
|
||||
#include "mdns_networking.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef MDNS_ENABLE_DEBUG
|
||||
void mdns_debug_packet(const uint8_t * data, size_t len);
|
||||
@ -38,7 +24,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len);
|
||||
static const char * MDNS_DEFAULT_DOMAIN = "local";
|
||||
static const char * MDNS_SUB_STR = "_sub";
|
||||
|
||||
static mdns_server_t * _mdns_server = NULL;
|
||||
mdns_server_t * _mdns_server = NULL;
|
||||
|
||||
static volatile TaskHandle_t _mdns_service_task_handle = NULL;
|
||||
static SemaphoreHandle_t _mdns_service_semaphore = NULL;
|
||||
@ -110,14 +96,7 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
* */
|
||||
|
||||
/**
|
||||
* @brief Queue RX packet action
|
||||
*/
|
||||
static esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet)
|
||||
esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet)
|
||||
{
|
||||
mdns_action_t * action = NULL;
|
||||
|
||||
@ -135,286 +114,6 @@ static esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the receive callback of the raw udp api. Packets are received here
|
||||
*
|
||||
*/
|
||||
static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport)
|
||||
{
|
||||
uint8_t i;
|
||||
while (pb != NULL) {
|
||||
struct pbuf * this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
|
||||
mdns_rx_packet_t * packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t));
|
||||
if (!packet) {
|
||||
//missed packet - no memory
|
||||
pbuf_free(this_pb);
|
||||
continue;
|
||||
}
|
||||
|
||||
packet->tcpip_if = TCPIP_ADAPTER_IF_MAX;
|
||||
packet->pb = this_pb;
|
||||
packet->src_port = rport;
|
||||
memcpy(&packet->src, raddr, sizeof(ip_addr_t));
|
||||
packet->dest.type = packet->src.type;
|
||||
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
packet->ip_protocol = MDNS_IP_PROTOCOL_V4;
|
||||
struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN);
|
||||
packet->dest.u_addr.ip4.addr = iphdr->dest.addr;
|
||||
} else {
|
||||
packet->ip_protocol = MDNS_IP_PROTOCOL_V6;
|
||||
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN);
|
||||
memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
|
||||
}
|
||||
packet->multicast = ip_addr_ismulticast(&(packet->dest));
|
||||
|
||||
//lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
|
||||
struct netif * netif = NULL;
|
||||
void * nif = NULL;
|
||||
struct udp_pcb * pcb = NULL;
|
||||
for (i=0; i<TCPIP_ADAPTER_IF_MAX; i++) {
|
||||
pcb = _mdns_server->interfaces[i].pcbs[packet->ip_protocol].pcb;
|
||||
tcpip_adapter_get_netif (i, &nif);
|
||||
netif = (struct netif *)nif;
|
||||
if (pcb && netif && netif == ip_current_input_netif ()) {
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) {
|
||||
//packet source is not in the same subnet
|
||||
pcb = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet->tcpip_if = i;
|
||||
break;
|
||||
}
|
||||
pcb = NULL;
|
||||
}
|
||||
|
||||
if (!pcb || !_mdns_server || !_mdns_server->action_queue
|
||||
|| _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
pbuf_free(this_pb);
|
||||
free(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB Main code
|
||||
*/
|
||||
static void _udp_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return;
|
||||
}
|
||||
mdns_pcb_t * _pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol];
|
||||
if (_pcb->pcb) {
|
||||
_pcb->state = PCB_OFF;
|
||||
udp_recv(_pcb->pcb, NULL, NULL);
|
||||
udp_disconnect(_pcb->pcb);
|
||||
udp_remove(_pcb->pcb);
|
||||
free(_pcb->probe_services);
|
||||
_pcb->pcb = NULL;
|
||||
_pcb->probe_ip = false;
|
||||
_pcb->probe_services = NULL;
|
||||
_pcb->probe_services_len = 0;
|
||||
_pcb->probe_running = false;
|
||||
_pcb->failed_probes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB V4
|
||||
*/
|
||||
static esp_err_t _udp_pcb_v4_init(tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
tcpip_adapter_ip_info_t if_ip_info;
|
||||
|
||||
if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tcpip_adapter_get_ip_info(tcpip_if, &if_ip_info) || if_ip_info.ip.addr == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ip_addr_t interface_addr = IPADDR4_INIT(if_ip_info.ip.addr);
|
||||
|
||||
ip_addr_t multicast_addr;
|
||||
IP_ADDR4(&multicast_addr, 224, 0, 0, 251);
|
||||
|
||||
if (igmp_joingroup((const struct ip4_addr *)&interface_addr.u_addr.ip4, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V4);
|
||||
if (!pcb) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) {
|
||||
udp_remove(pcb);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
pcb->mcast_ttl = 1;
|
||||
pcb->remote_port = MDNS_SERVICE_PORT;
|
||||
ip_addr_copy(pcb->multicast_ip, interface_addr);
|
||||
ip_addr_copy(pcb->remote_ip, multicast_addr);
|
||||
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb = pcb;
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].failed_probes = 0;
|
||||
udp_recv(pcb, &_udp_recv, _mdns_server);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB V6
|
||||
*/
|
||||
static esp_err_t _udp_pcb_v6_init(tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000);
|
||||
ip_addr_t interface_addr;
|
||||
interface_addr.type = IPADDR_TYPE_V6;
|
||||
|
||||
if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tcpip_adapter_get_ip6_linklocal(tcpip_if, &interface_addr.u_addr.ip6)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (mld6_joingroup(&(interface_addr.u_addr.ip6), &(multicast_addr.u_addr.ip6))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V6);
|
||||
if (!pcb) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) {
|
||||
udp_remove(pcb);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
pcb->remote_port = MDNS_SERVICE_PORT;
|
||||
ip_addr_copy(pcb->remote_ip, multicast_addr);
|
||||
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb = pcb;
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].failed_probes = 0;
|
||||
udp_recv(pcb, &_udp_recv, _mdns_server);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB Main code
|
||||
*/
|
||||
static esp_err_t _udp_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
|
||||
return _udp_pcb_v4_init(tcpip_if);
|
||||
} else if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
|
||||
return _udp_pcb_v6_init(tcpip_if);
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct tcpip_api_call call;
|
||||
tcpip_adapter_if_t tcpip_if;
|
||||
mdns_ip_protocol_t ip_protocol;
|
||||
esp_err_t err;
|
||||
} mdns_api_call_t;
|
||||
|
||||
/**
|
||||
* @brief Start PCB from LwIP thread
|
||||
*/
|
||||
static err_t _mdns_pcb_init_api(struct tcpip_api_call *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg;
|
||||
msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol);
|
||||
return msg->err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB
|
||||
*/
|
||||
static esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol
|
||||
};
|
||||
tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB from LwIP thread
|
||||
*/
|
||||
static err_t _mdns_pcb_deinit_api(struct tcpip_api_call *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg;
|
||||
_udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol);
|
||||
msg->err = ESP_OK;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB
|
||||
*/
|
||||
static esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol
|
||||
};
|
||||
tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief send packet over UDP
|
||||
*
|
||||
* @param server The server
|
||||
* @param data byte array containing the packet data
|
||||
* @param len length of the packet data
|
||||
*
|
||||
* @return length of sent packet or 0 on error
|
||||
*/
|
||||
static size_t _udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len)
|
||||
{
|
||||
#ifndef MDNS_TEST_MODE
|
||||
struct netif * netif = NULL;
|
||||
void * nif = NULL;
|
||||
esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif);
|
||||
netif = (struct netif *)nif;
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if (pbt == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memcpy((uint8_t *)pbt->payload, data, len);
|
||||
|
||||
err = udp_sendto_if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb, pbt, ip, port, netif);
|
||||
pbuf_free(pbt);
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the service name of a service
|
||||
*/
|
||||
@ -1235,7 +934,7 @@ static void _mdns_dispatch_tx_packet(mdns_tx_packet_t * p)
|
||||
mdns_debug_packet(packet, index);
|
||||
#endif
|
||||
|
||||
_udp_pcb_write(p->tcpip_if, p->ip_protocol, &p->dst, p->port, packet, index);
|
||||
_mdns_udp_pcb_write(p->tcpip_if, p->ip_protocol, &p->dst, p->port, packet, index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4192,7 +3891,6 @@ static esp_err_t _mdns_stop_timer(){
|
||||
*/
|
||||
static esp_err_t _mdns_service_task_start()
|
||||
{
|
||||
#ifndef MDNS_TEST_MODE
|
||||
if (!_mdns_service_semaphore) {
|
||||
_mdns_service_semaphore = xSemaphoreCreateMutex();
|
||||
if (!_mdns_service_semaphore) {
|
||||
@ -4212,8 +3910,6 @@ static esp_err_t _mdns_service_task_start()
|
||||
}
|
||||
}
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -4225,7 +3921,6 @@ static esp_err_t _mdns_service_task_start()
|
||||
*/
|
||||
static esp_err_t _mdns_service_task_stop()
|
||||
{
|
||||
#ifndef MDNS_TEST_MODE
|
||||
MDNS_SERVICE_LOCK();
|
||||
_mdns_stop_timer();
|
||||
if (_mdns_service_task_handle) {
|
||||
@ -4241,7 +3936,6 @@ static esp_err_t _mdns_service_task_stop()
|
||||
}
|
||||
}
|
||||
MDNS_SERVICE_UNLOCK();
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
284
components/mdns/mdns_networking.c
Normal file
284
components/mdns/mdns_networking.c
Normal file
@ -0,0 +1,284 @@
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "mdns_networking.h"
|
||||
|
||||
|
||||
extern mdns_server_t * _mdns_server;
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief the receive callback of the raw udp api. Packets are received here
|
||||
*
|
||||
*/
|
||||
static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport)
|
||||
{
|
||||
|
||||
uint8_t i;
|
||||
while (pb != NULL) {
|
||||
struct pbuf * this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
|
||||
mdns_rx_packet_t * packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t));
|
||||
if (!packet) {
|
||||
//missed packet - no memory
|
||||
pbuf_free(this_pb);
|
||||
continue;
|
||||
}
|
||||
|
||||
packet->tcpip_if = TCPIP_ADAPTER_IF_MAX;
|
||||
packet->pb = this_pb;
|
||||
packet->src_port = rport;
|
||||
memcpy(&packet->src, raddr, sizeof(ip_addr_t));
|
||||
packet->dest.type = packet->src.type;
|
||||
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
packet->ip_protocol = MDNS_IP_PROTOCOL_V4;
|
||||
struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN);
|
||||
packet->dest.u_addr.ip4.addr = iphdr->dest.addr;
|
||||
} else {
|
||||
packet->ip_protocol = MDNS_IP_PROTOCOL_V6;
|
||||
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN);
|
||||
memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
|
||||
}
|
||||
packet->multicast = ip_addr_ismulticast(&(packet->dest));
|
||||
|
||||
//lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
|
||||
struct netif * netif = NULL;
|
||||
void * nif = NULL;
|
||||
struct udp_pcb * pcb = NULL;
|
||||
for (i=0; i<TCPIP_ADAPTER_IF_MAX; i++) {
|
||||
pcb = _mdns_server->interfaces[i].pcbs[packet->ip_protocol].pcb;
|
||||
tcpip_adapter_get_netif (i, &nif);
|
||||
netif = (struct netif *)nif;
|
||||
if (pcb && netif && netif == ip_current_input_netif ()) {
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) {
|
||||
//packet source is not in the same subnet
|
||||
pcb = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packet->tcpip_if = i;
|
||||
break;
|
||||
}
|
||||
pcb = NULL;
|
||||
}
|
||||
|
||||
if (!pcb || !_mdns_server || !_mdns_server->action_queue
|
||||
|| _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
pbuf_free(this_pb);
|
||||
free(packet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB Main code
|
||||
*/
|
||||
static void _udp_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (!_mdns_server) {
|
||||
return;
|
||||
}
|
||||
mdns_pcb_t * _pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol];
|
||||
if (_pcb->pcb) {
|
||||
_pcb->state = PCB_OFF;
|
||||
udp_recv(_pcb->pcb, NULL, NULL);
|
||||
udp_disconnect(_pcb->pcb);
|
||||
udp_remove(_pcb->pcb);
|
||||
free(_pcb->probe_services);
|
||||
_pcb->pcb = NULL;
|
||||
_pcb->probe_ip = false;
|
||||
_pcb->probe_services = NULL;
|
||||
_pcb->probe_services_len = 0;
|
||||
_pcb->probe_running = false;
|
||||
_pcb->failed_probes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB V4
|
||||
*/
|
||||
static esp_err_t _udp_pcb_v4_init(tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
tcpip_adapter_ip_info_t if_ip_info;
|
||||
|
||||
if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tcpip_adapter_get_ip_info(tcpip_if, &if_ip_info) || if_ip_info.ip.addr == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ip_addr_t interface_addr = IPADDR4_INIT(if_ip_info.ip.addr);
|
||||
|
||||
ip_addr_t multicast_addr;
|
||||
IP_ADDR4(&multicast_addr, 224, 0, 0, 251);
|
||||
|
||||
if (igmp_joingroup((const struct ip4_addr *)&interface_addr.u_addr.ip4, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V4);
|
||||
if (!pcb) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) {
|
||||
udp_remove(pcb);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
pcb->mcast_ttl = 1;
|
||||
pcb->remote_port = MDNS_SERVICE_PORT;
|
||||
ip_addr_copy(pcb->multicast_ip, interface_addr);
|
||||
ip_addr_copy(pcb->remote_ip, multicast_addr);
|
||||
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb = pcb;
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].failed_probes = 0;
|
||||
udp_recv(pcb, &_udp_recv, _mdns_server);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB V6
|
||||
*/
|
||||
static esp_err_t _udp_pcb_v6_init(tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000);
|
||||
ip_addr_t interface_addr;
|
||||
interface_addr.type = IPADDR_TYPE_V6;
|
||||
|
||||
if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (tcpip_adapter_get_ip6_linklocal(tcpip_if, &interface_addr.u_addr.ip6)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (mld6_joingroup(&(interface_addr.u_addr.ip6), &(multicast_addr.u_addr.ip6))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
struct udp_pcb * pcb = udp_new_ip_type(IPADDR_TYPE_V6);
|
||||
if (!pcb) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
if (udp_bind(pcb, &interface_addr, MDNS_SERVICE_PORT) != 0) {
|
||||
udp_remove(pcb);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
pcb->remote_port = MDNS_SERVICE_PORT;
|
||||
ip_addr_copy(pcb->remote_ip, multicast_addr);
|
||||
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb = pcb;
|
||||
_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].failed_probes = 0;
|
||||
udp_recv(pcb, &_udp_recv, _mdns_server);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB Main code
|
||||
*/
|
||||
static esp_err_t _udp_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
|
||||
return _udp_pcb_v4_init(tcpip_if);
|
||||
} else if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
|
||||
return _udp_pcb_v6_init(tcpip_if);
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct tcpip_api_call call;
|
||||
tcpip_adapter_if_t tcpip_if;
|
||||
mdns_ip_protocol_t ip_protocol;
|
||||
esp_err_t err;
|
||||
} mdns_api_call_t;
|
||||
|
||||
/**
|
||||
* @brief Start PCB from LwIP thread
|
||||
*/
|
||||
static err_t _mdns_pcb_init_api(struct tcpip_api_call *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg;
|
||||
msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol);
|
||||
return msg->err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB from LwIP thread
|
||||
*/
|
||||
static err_t _mdns_pcb_deinit_api(struct tcpip_api_call *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg;
|
||||
_udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol);
|
||||
msg->err = ESP_OK;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-static functions below are
|
||||
* - _mdns prefixed
|
||||
* - commented in mdns_networking.h header
|
||||
*/
|
||||
esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol
|
||||
};
|
||||
tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol
|
||||
};
|
||||
tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
size_t _mdns_udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len)
|
||||
{
|
||||
struct netif * netif = NULL;
|
||||
void * nif = NULL;
|
||||
esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif);
|
||||
netif = (struct netif *)nif;
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if (pbt == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memcpy((uint8_t *)pbt->payload, data, len);
|
||||
|
||||
err = udp_sendto_if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb, pbt, ip, port, netif);
|
||||
pbuf_free(pbt);
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
52
components/mdns/private_include/mdns_networking.h
Normal file
52
components/mdns/private_include/mdns_networking.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef ESP_MDNS_NETWORKING_H_
|
||||
#define ESP_MDNS_NETWORKING_H_
|
||||
|
||||
/*
|
||||
* MDNS Server Networking -- private include
|
||||
*
|
||||
*/
|
||||
#include "mdns.h"
|
||||
#include "mdns_private.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_event_loop.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Queue RX packet action
|
||||
*/
|
||||
esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet);
|
||||
|
||||
/**
|
||||
* @brief Start PCB
|
||||
*/
|
||||
esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
/**
|
||||
* @brief Stop PCB
|
||||
*/
|
||||
esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
/**
|
||||
* @brief send packet over UDP
|
||||
*
|
||||
* @param server The server
|
||||
* @param data byte array containing the packet data
|
||||
* @param len length of the packet data
|
||||
*
|
||||
* @return length of sent packet or 0 on error
|
||||
*/
|
||||
size_t _mdns_udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len);
|
||||
|
||||
#endif /* ESP_MDNS_NETWORKING_H_ */
|
@ -1,17 +1,25 @@
|
||||
TEST_NAME=test
|
||||
FUZZ=afl-fuzz
|
||||
CC=afl-clang-fast
|
||||
COMPONENTS_DIR=../..
|
||||
CFLAGS=-g -DMDNS_TEST_MODE -I. -I.. -I../include -I../private_include -I$(COMPONENTS_DIR)/tcpip_adapter/include -I$(COMPONENTS_DIR)/esp32/include -include esp32_compat.h
|
||||
MDNS_C_DEPENDENCY_INJECTION=-include mdns_di.h
|
||||
ifeq ($(INSTR),off)
|
||||
CC=gcc
|
||||
CFLAGS+=-DINSTR_IS_OFF
|
||||
TEST_NAME=test_sim
|
||||
else
|
||||
CC=afl-clang-fast
|
||||
endif
|
||||
CPP=$(CC)
|
||||
LD=$(CC)
|
||||
OBJECTS=mdns.o test.o
|
||||
CFLAGS=-DMDNS_TEST_MODE -I. -I../include
|
||||
OBJECTS=mdns.o esp32_mock.o test.o
|
||||
|
||||
OS := $(shell uname)
|
||||
ifeq ($(OS),Darwin)
|
||||
LDLIBS=
|
||||
else
|
||||
LDLIBS=-lbsd
|
||||
CFLAGS+=-DUSE_BSD_STRING
|
||||
LDLIBS=-lbsd
|
||||
CFLAGS+=-DUSE_BSD_STRING
|
||||
endif
|
||||
|
||||
all: $(TEST_NAME)
|
||||
@ -22,11 +30,11 @@ all: $(TEST_NAME)
|
||||
|
||||
mdns.o: ../mdns.c
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
@$(CC) $(CFLAGS) $(MDNS_C_DEPENDENCY_INJECTION) -c $< -o $@
|
||||
|
||||
$(TEST_NAME): $(OBJECTS)
|
||||
@echo "[LD] $@"
|
||||
@$(LD) $(LDLIBS) $(OBJECTS) -o $@
|
||||
@$(LD) $(OBJECTS) -o $@ $(LDLIBS)
|
||||
|
||||
fuzz: $(TEST_NAME)
|
||||
@$(FUZZ) -i "in" -o "out" -- ./$(TEST_NAME)
|
||||
|
@ -17,6 +17,12 @@
|
||||
|
||||
#ifdef MDNS_TEST_MODE
|
||||
|
||||
// Not to include
|
||||
#define ESP_MDNS_NETWORKING_H_
|
||||
#define _TCPIP_ADAPTER_H_
|
||||
#define __ESP_EVENT_H__
|
||||
|
||||
|
||||
#ifdef USE_BSD_STRING
|
||||
#include <bsd/string.h>
|
||||
#endif
|
||||
@ -28,6 +34,7 @@
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
||||
#define ERR_OK 0
|
||||
#define ESP_OK 0
|
||||
#define ESP_FAIL -1
|
||||
@ -44,21 +51,26 @@
|
||||
|
||||
#define pdTRUE true
|
||||
#define pdFALSE false
|
||||
#define pdPASS ( pdTRUE )
|
||||
#define pdFAIL ( pdFALSE )
|
||||
|
||||
#define portMAX_DELAY 0xFFFFFFFF
|
||||
#define portTICK_PERIOD_MS 1
|
||||
|
||||
#define xSemaphoreTake(s,d)
|
||||
#define xTaskDelete(a)
|
||||
#define vTaskDelete(a) free(a)
|
||||
#define xSemaphoreGive(s)
|
||||
#define _mdns_pcb_init(a,b) true
|
||||
#define _mdns_pcb_deinit(a,b) true
|
||||
#define xSemaphoreCreateMutex() malloc(1)
|
||||
#define vSemaphoreDelete(s) free(s)
|
||||
#define xQueueCreate(n,s) malloc((n)*(s))
|
||||
#define vQueueDelete(q) free(q)
|
||||
#define xQueueReceive(q, d, t) (ESP_OK)
|
||||
#define vTaskDelay(m) usleep((m)*1000)
|
||||
#define xTaskCreatePinnedToCore(a,b,c,d,e,f,g) *(f) = malloc(1)
|
||||
#define vTaskDelay(m) usleep((m)*0)
|
||||
#define pbuf_free(p) free(p)
|
||||
|
||||
#define tcpip_adapter_get_ip_info(i,d)
|
||||
#define esp_random() (rand()%UINT32_MAX)
|
||||
#define tcpip_adapter_get_ip_info(i,d) true
|
||||
#define tcpip_adapter_dhcpc_get_status(a, b) TCPIP_ADAPTER_DHCP_STARTED
|
||||
#define tcpip_adapter_get_ip6_linklocal(i,d) (ESP_OK)
|
||||
#define tcpip_adapter_get_hostname(i, n) *(n) = "esp32-0123456789AB"
|
||||
|
||||
@ -67,17 +79,31 @@
|
||||
((uint32_t)((c) & 0xff) << 16) | \
|
||||
((uint32_t)((b) & 0xff) << 8) | \
|
||||
(uint32_t)((a) & 0xff)
|
||||
#define ip_2_ip6(ipaddr) (&((ipaddr)->u_addr.ip6))
|
||||
#define ip_2_ip4(ipaddr) (&((ipaddr)->u_addr.ip4))
|
||||
|
||||
#define IPADDR_TYPE_V4 0U
|
||||
#define IPADDR_TYPE_V6 6U
|
||||
#define IPADDR_TYPE_ANY 46U
|
||||
#define IP_SET_TYPE_VAL(ipaddr, iptype) do { (ipaddr).type = (iptype); }while(0)
|
||||
#define IP_ADDR4(ipaddr,a,b,c,d) do { IP4_ADDR(ip_2_ip4(ipaddr),a,b,c,d); \
|
||||
IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V4); } while(0)
|
||||
#define IP_ADDR6(ipaddr,i0,i1,i2,i3) do { IP6_ADDR(ip_2_ip6(ipaddr),i0,i1,i2,i3); \
|
||||
IP_SET_TYPE_VAL(*(ipaddr), IPADDR_TYPE_V6); } while(0)
|
||||
|
||||
#define IPADDR6_INIT(a, b, c, d) { { { { a, b, c, d } } }, IPADDR_TYPE_V6 }
|
||||
|
||||
typedef int32_t esp_err_t;
|
||||
|
||||
typedef void * xSemaphoreHandle;
|
||||
typedef void * SemaphoreHandle_t;
|
||||
typedef void * xQueueHandle;
|
||||
typedef void * QueueHandle_t;
|
||||
typedef void * TaskHandle_t;
|
||||
typedef void * esp_timer_handle_t;
|
||||
typedef uint32_t TickType_t;
|
||||
typedef uint32_t portTickType;
|
||||
|
||||
typedef enum {
|
||||
TCPIP_ADAPTER_IF_STA = 0, /**< ESP32 station interface */
|
||||
TCPIP_ADAPTER_IF_AP, /**< ESP32 soft-AP interface */
|
||||
TCPIP_ADAPTER_IF_ETH, /**< ESP32 ethernet interface */
|
||||
TCPIP_ADAPTER_IF_MAX
|
||||
} tcpip_adapter_if_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_MODE_NULL = 0, /**< null mode */
|
||||
@ -87,6 +113,42 @@ typedef enum {
|
||||
WIFI_MODE_MAX
|
||||
} wifi_mode_t;
|
||||
|
||||
/* status of DHCP client or DHCP server */
|
||||
typedef enum {
|
||||
TCPIP_ADAPTER_DHCP_INIT = 0, /**< DHCP client/server in initial state */
|
||||
TCPIP_ADAPTER_DHCP_STARTED, /**< DHCP client/server already been started */
|
||||
TCPIP_ADAPTER_DHCP_STOPPED, /**< DHCP client/server already been stopped */
|
||||
TCPIP_ADAPTER_DHCP_STATUS_MAX
|
||||
} tcpip_adapter_dhcp_status_t;
|
||||
|
||||
typedef enum {
|
||||
SYSTEM_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */
|
||||
SYSTEM_EVENT_SCAN_DONE, /**< ESP32 finish scanning AP */
|
||||
SYSTEM_EVENT_STA_START, /**< ESP32 station start */
|
||||
SYSTEM_EVENT_STA_STOP, /**< ESP32 station stop */
|
||||
SYSTEM_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
||||
SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
|
||||
SYSTEM_EVENT_STA_GOT_IP, /**< ESP32 station got IP from connected AP */
|
||||
SYSTEM_EVENT_STA_LOST_IP, /**< ESP32 station lost IP and the IP is reset to 0 */
|
||||
SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
|
||||
SYSTEM_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
|
||||
SYSTEM_EVENT_AP_START, /**< ESP32 soft-AP start */
|
||||
SYSTEM_EVENT_AP_STOP, /**< ESP32 soft-AP stop */
|
||||
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
|
||||
SYSTEM_EVENT_GOT_IP6, /**< ESP32 station or ap or ethernet interface v6IP addr is preferred */
|
||||
SYSTEM_EVENT_ETH_START, /**< ESP32 ethernet start */
|
||||
SYSTEM_EVENT_ETH_STOP, /**< ESP32 ethernet stop */
|
||||
SYSTEM_EVENT_ETH_CONNECTED, /**< ESP32 ethernet phy link up */
|
||||
SYSTEM_EVENT_ETH_DISCONNECTED, /**< ESP32 ethernet phy link down */
|
||||
SYSTEM_EVENT_ETH_GOT_IP, /**< ESP32 ethernet got IP from connected AP */
|
||||
SYSTEM_EVENT_MAX
|
||||
} system_event_id_t;
|
||||
|
||||
struct udp_pcb {
|
||||
uint8_t dummy;
|
||||
};
|
||||
@ -101,27 +163,76 @@ struct ip6_addr {
|
||||
};
|
||||
typedef struct ip6_addr ip6_addr_t;
|
||||
|
||||
typedef struct _ip_addr {
|
||||
union {
|
||||
ip6_addr_t ip6;
|
||||
ip4_addr_t ip4;
|
||||
} u_addr;
|
||||
uint8_t type;
|
||||
} ip_addr_t;
|
||||
|
||||
typedef struct {
|
||||
ip4_addr_t ip;
|
||||
ip4_addr_t netmask;
|
||||
ip4_addr_t gw;
|
||||
} tcpip_adapter_ip_info_t;
|
||||
|
||||
// typedef int32_t system_event_id_t;
|
||||
typedef enum {
|
||||
TCPIP_ADAPTER_IF_STA = 0, /**< ESP32 station interface */
|
||||
TCPIP_ADAPTER_IF_AP, /**< ESP32 soft-AP interface */
|
||||
TCPIP_ADAPTER_IF_ETH, /**< ESP32 ethernet interface */
|
||||
TCPIP_ADAPTER_IF_MAX
|
||||
} tcpip_adapter_if_t;
|
||||
|
||||
typedef struct {
|
||||
ip6_addr_t ip;
|
||||
} tcpip_adapter_ip6_info_t;
|
||||
typedef struct {
|
||||
tcpip_adapter_if_t if_index;
|
||||
tcpip_adapter_ip6_info_t ip6_info;
|
||||
} system_event_got_ip6_t;
|
||||
typedef union {
|
||||
system_event_got_ip6_t got_ip6; /**< ESP32 station or ap or ethernet ipv6 addr state change to preferred */
|
||||
} system_event_info_t;
|
||||
|
||||
typedef struct {
|
||||
system_event_id_t event_id; /**< event ID */
|
||||
system_event_info_t event_info; /**< event information */
|
||||
} system_event_t;
|
||||
|
||||
inline esp_err_t esp_wifi_get_mode(wifi_mode_t * mode)
|
||||
{
|
||||
*mode = WIFI_MODE_APSTA;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
inline uint32_t xTaskGetTickCount()
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
if (gettimeofday(&tv, &tz) == 0) {
|
||||
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
struct pbuf {
|
||||
struct pbuf *next;
|
||||
void *payload;
|
||||
uint16_t tot_len;
|
||||
uint16_t len;
|
||||
uint8_t /*pbuf_type*/ type;
|
||||
uint8_t flags;
|
||||
uint16_t ref;
|
||||
};
|
||||
|
||||
#define IP_GET_TYPE(ipaddr) ((ipaddr)->type)
|
||||
#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6)
|
||||
#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr)
|
||||
#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \
|
||||
(dest).addr[1] = (src).addr[1]; \
|
||||
(dest).addr[2] = (src).addr[2]; \
|
||||
(dest).addr[3] = (src).addr[3];}while(0)
|
||||
|
||||
#define ip_addr_copy(dest, src) do{ IP_SET_TYPE_VAL(dest, IP_GET_TYPE(&src)); if(IP_IS_V6_VAL(src)){ \
|
||||
ip6_addr_copy(*ip_2_ip6(&(dest)), *ip_2_ip6(&(src))); }else{ \
|
||||
ip4_addr_copy(*ip_2_ip4(&(dest)), *ip_2_ip4(&(src))); }}while(0)
|
||||
|
||||
#include "esp32_mock.h"
|
||||
|
||||
uint32_t xTaskGetTickCount();
|
||||
|
||||
|
||||
#endif //MDNS_TEST_MODE
|
||||
|
||||
|
84
components/mdns/test_afl_fuzz_host/esp32_mock.c
Normal file
84
components/mdns/test_afl_fuzz_host/esp32_mock.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "esp32_compat.h"
|
||||
|
||||
void* g_queue;
|
||||
int g_queue_send_shall_fail = 0;
|
||||
int g_size = 0;
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_stop(esp_timer_handle_t timer)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args,
|
||||
esp_timer_handle_t* out_handle)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t xTaskGetTickCount()
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
if (gettimeofday(&tv, &tz) == 0) {
|
||||
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Queue mock
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
{
|
||||
g_size = uxItemSize;
|
||||
g_queue = malloc((uxQueueLength)*(uxItemSize));
|
||||
return g_queue;
|
||||
}
|
||||
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
{
|
||||
free(xQueue);
|
||||
}
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
if (g_queue_send_shall_fail)
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(xQueue, pvItemToQueue, g_size);
|
||||
return pdPASS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
void GetLastItem(void *pvBuffer)
|
||||
{
|
||||
memcpy(pvBuffer, g_queue, g_size);
|
||||
}
|
||||
|
||||
void ForceTaskDelete()
|
||||
{
|
||||
g_queue_send_shall_fail = 1;
|
||||
}
|
45
components/mdns/test_afl_fuzz_host/esp32_mock.h
Normal file
45
components/mdns/test_afl_fuzz_host/esp32_mock.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef ESP32_MOCK_H_
|
||||
#define ESP32_MOCK_H_
|
||||
|
||||
typedef void (*esp_timer_cb_t)(void* arg);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ESP_TIMER_TASK, //!< Callback is called from timer task
|
||||
} esp_timer_dispatch_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
esp_timer_cb_t callback; //!< Function to call when timer expires
|
||||
void* arg; //!< Argument to pass to the callback
|
||||
esp_timer_dispatch_t dispatch_method; //!< Call the callback from task or from ISR
|
||||
const char* name; //!< Timer name, used in esp_timer_dump function
|
||||
} esp_timer_create_args_t;
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
||||
|
||||
esp_err_t esp_timer_stop(esp_timer_handle_t timer);
|
||||
|
||||
esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);
|
||||
|
||||
esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args,
|
||||
esp_timer_handle_t* out_handle);
|
||||
|
||||
|
||||
// Queue mock
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize );
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue );
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
|
||||
|
||||
void GetLastItem(void *pvBuffer);
|
||||
|
||||
void ForceTaskDelete();
|
||||
|
||||
#define _mdns_udp_pcb_write(tcpip_if, ip_protocol, ip, port, data, len) len
|
||||
|
||||
#endif /* ESP32_MOCK_H_ */
|
53
components/mdns/test_afl_fuzz_host/mdns_di.h
Normal file
53
components/mdns/test_afl_fuzz_host/mdns_di.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* MDNS Dependecy injection -- preincluded to inject interface test functions into static variables
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mdns.h"
|
||||
#include "mdns_private.h"
|
||||
|
||||
void (*mdns_test_static_execute_action)(mdns_action_t *) = NULL;
|
||||
mdns_srv_item_t * (*mdns_test_static_mdns_get_service_item)(const char * service, const char * proto) = NULL;
|
||||
mdns_search_once_t * (*mdns_test_static_search_init)(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results) = NULL;
|
||||
esp_err_t (*mdns_test_static_send_search_action)(mdns_action_type_t type, mdns_search_once_t * search) = NULL;
|
||||
void (*mdns_test_static_search_free)(mdns_search_once_t * search) = NULL;
|
||||
|
||||
static void _mdns_execute_action(mdns_action_t * action);
|
||||
static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto);
|
||||
static mdns_search_once_t * _mdns_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results);
|
||||
static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_once_t * search);
|
||||
static void _mdns_search_free(mdns_search_once_t * search);
|
||||
|
||||
void mdns_test_init_di()
|
||||
{
|
||||
mdns_test_static_execute_action = _mdns_execute_action;
|
||||
mdns_test_static_mdns_get_service_item = _mdns_get_service_item;
|
||||
mdns_test_static_search_init = _mdns_search_init;
|
||||
mdns_test_static_send_search_action = _mdns_send_search_action;
|
||||
mdns_test_static_search_free = _mdns_search_free;
|
||||
}
|
||||
|
||||
void mdns_test_execute_action(void * action)
|
||||
{
|
||||
mdns_test_static_execute_action((mdns_action_t *)action);
|
||||
}
|
||||
|
||||
void mdns_test_search_free(mdns_search_once_t * search)
|
||||
{
|
||||
return mdns_test_static_search_free(search);
|
||||
}
|
||||
|
||||
esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t * search)
|
||||
{
|
||||
return mdns_test_static_send_search_action(type, search);
|
||||
}
|
||||
|
||||
mdns_search_once_t * mdns_test_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results)
|
||||
{
|
||||
return mdns_test_static_search_init(name, service, proto, type, timeout, max_results);
|
||||
}
|
||||
|
||||
mdns_srv_item_t * mdns_test_mdns_get_service_item(const char * service, const char * proto)
|
||||
{
|
||||
return mdns_test_static_mdns_get_service_item(service, proto);
|
||||
}
|
@ -12,8 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef MDNS_TEST_MODE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -21,93 +19,210 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mdns.h"
|
||||
#include "mdns_private.h"
|
||||
|
||||
void mdns_parse_packet(mdns_server_t * server, const uint8_t * data, size_t len);
|
||||
//
|
||||
// Global stuctures containing packet payload, search
|
||||
mdns_rx_packet_t g_packet;
|
||||
struct pbuf mypbuf;
|
||||
mdns_search_once_t * search = NULL;
|
||||
|
||||
//
|
||||
// Dependency injected test functions
|
||||
void mdns_test_execute_action(void * action);
|
||||
mdns_srv_item_t * mdns_test_mdns_get_service_item(const char * service, const char * proto);
|
||||
mdns_search_once_t * mdns_test_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results);
|
||||
esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t * search);
|
||||
void mdns_test_search_free(mdns_search_once_t * search);
|
||||
void mdns_test_init_di();
|
||||
|
||||
//
|
||||
// mdns function wrappers for mdns setup in test mode
|
||||
static int mdns_test_hostname_set(const char * mdns_hostname)
|
||||
{
|
||||
int ret = mdns_hostname_set(mdns_hostname);
|
||||
mdns_action_t * a = NULL;
|
||||
GetLastItem(&a);
|
||||
mdns_test_execute_action(a);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdns_test_service_instance_name_set(const char * service, const char * proto, const char * instance)
|
||||
{
|
||||
int ret = mdns_service_instance_name_set(service, proto, instance);
|
||||
mdns_action_t * a = NULL;
|
||||
GetLastItem(&a);
|
||||
mdns_test_execute_action(a);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdns_test_service_txt_set(const char * service, const char * proto, uint8_t num_items, mdns_txt_item_t txt[])
|
||||
{
|
||||
int ret = mdns_service_txt_set(service, proto, txt, num_items);
|
||||
mdns_action_t * a = NULL;
|
||||
GetLastItem(&a);
|
||||
mdns_test_execute_action(a);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdns_test_service_add(const char * service_name, const char * proto, uint32_t port)
|
||||
{
|
||||
if (mdns_service_add(NULL, service_name, proto, port, NULL, 0)) {
|
||||
// This is expected failure as the service thread is not running
|
||||
}
|
||||
mdns_action_t * a = NULL;
|
||||
GetLastItem(&a);
|
||||
mdns_test_execute_action(a);
|
||||
|
||||
if (mdns_test_mdns_get_service_item(service_name, proto)==NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static mdns_result_t* mdns_test_query(const char * service_name, const char * proto)
|
||||
{
|
||||
search = mdns_test_search_init(NULL, service_name, proto, MDNS_TYPE_PTR, 3000, 20);
|
||||
if (!search) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_test_send_search_action(ACTION_SEARCH_ADD, search)) {
|
||||
mdns_test_search_free(search);
|
||||
abort();
|
||||
}
|
||||
|
||||
mdns_action_t * a = NULL;
|
||||
GetLastItem(&a);
|
||||
mdns_test_execute_action(a);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void mdns_test_query_free()
|
||||
{
|
||||
mdns_test_search_free(search);
|
||||
}
|
||||
|
||||
//
|
||||
// function "under test" where afl-mangled packets passed
|
||||
//
|
||||
void mdns_parse_packet(mdns_rx_packet_t * packet);
|
||||
|
||||
//
|
||||
// Test starts here
|
||||
//
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i;
|
||||
const char * mdns_hostname = "minifritz";
|
||||
const char * mdns_instance = "Hristo's Time Capsule";
|
||||
const char * arduTxtData[4] = {
|
||||
"board=esp32",
|
||||
"tcp_check=no",
|
||||
"ssh_upload=no",
|
||||
"auth_upload=no"
|
||||
mdns_txt_item_t arduTxtData[4] = {
|
||||
{"board","esp32"},
|
||||
{"tcp_check","no"},
|
||||
{"ssh_upload","no"},
|
||||
{"auth_upload","no"}
|
||||
};
|
||||
|
||||
const uint8_t mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x32};
|
||||
|
||||
mdns_server_t * mdns = NULL;
|
||||
uint8_t buf[1460];
|
||||
char winstance[21+strlen(mdns_hostname)];
|
||||
|
||||
sprintf(winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", mdns_hostname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
if (mdns_init(TCPIP_ADAPTER_IF_ETH, &mdns)) {
|
||||
// Init depencency injected methods
|
||||
mdns_test_init_di();
|
||||
|
||||
if (mdns_init()) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_set_hostname(mdns, mdns_hostname)) {
|
||||
if (mdns_test_hostname_set(mdns_hostname)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_set_instance(mdns, mdns_instance)) {
|
||||
if (mdns_test_service_add("_workstation", "_tcp", 9)) {
|
||||
abort();
|
||||
}
|
||||
if (mdns_test_service_instance_name_set("_workstation", "_tcp", winstance)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_add(mdns, "_workstation", "_tcp", 9)) {
|
||||
if (mdns_test_service_add("_arduino", "_tcp", 3232)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_instance_set(mdns, "_workstation", "_tcp", winstance)) {
|
||||
if (mdns_test_service_txt_set("_arduino", "_tcp", 4, arduTxtData)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_add(mdns, "_arduino", "_tcp", 3232)) {
|
||||
if (mdns_test_service_add("_http", "_tcp", 80)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_txt_set(mdns, "_arduino", "_tcp", 4, arduTxtData)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_add(mdns, "_http", "_tcp", 80)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (mdns_service_instance_set(mdns, "_http", "_tcp", "ESP WebServer")) {
|
||||
if (mdns_test_service_instance_name_set("_http", "_tcp", "ESP WebServer")) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (
|
||||
mdns_service_add(mdns, "_afpovertcp", "_tcp", 548)
|
||||
|| mdns_service_add(mdns, "_rfb", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_smb", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_adisk", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_airport", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_printer", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_airplay", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_raop", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_uscan", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_uscans", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ippusb", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_scanner", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ipp", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ipps", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_pdl-datastream", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_ptp", "_tcp", 885)
|
||||
|| mdns_service_add(mdns, "_sleep-proxy", "_udp", 885))
|
||||
mdns_test_service_add("_afpovertcp", "_tcp", 548)
|
||||
|| mdns_test_service_add("_rfb", "_tcp", 885)
|
||||
|| mdns_test_service_add("_smb", "_tcp", 885)
|
||||
|| mdns_test_service_add("_adisk", "_tcp", 885)
|
||||
|| mdns_test_service_add("_airport", "_tcp", 885)
|
||||
|| mdns_test_service_add("_printer", "_tcp", 885)
|
||||
|| mdns_test_service_add("_airplay", "_tcp", 885)
|
||||
|| mdns_test_service_add("_raop", "_tcp", 885)
|
||||
|| mdns_test_service_add("_uscan", "_tcp", 885)
|
||||
|| mdns_test_service_add("_uscans", "_tcp", 885)
|
||||
|| mdns_test_service_add("_ippusb", "_tcp", 885)
|
||||
|| mdns_test_service_add("_scanner", "_tcp", 885)
|
||||
|| mdns_test_service_add("_ipp", "_tcp", 885)
|
||||
|| mdns_test_service_add("_ipps", "_tcp", 885)
|
||||
|| mdns_test_service_add("_pdl-datastream", "_tcp", 885)
|
||||
|| mdns_test_service_add("_ptp", "_tcp", 885)
|
||||
|| mdns_test_service_add("_sleep-proxy", "_udp", 885))
|
||||
{
|
||||
abort();
|
||||
abort();
|
||||
}
|
||||
|
||||
mdns_result_t * results = NULL;
|
||||
FILE *file;
|
||||
size_t nread;
|
||||
|
||||
#ifdef INSTR_IS_OFF
|
||||
size_t len = 1460;
|
||||
memset(buf, 0, 1460);
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
printf("Non-instrumentation mode: please supply a file name created by AFL to reproduce crash\n");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Note: parameter1 is a file (mangled packet) which caused the crash
|
||||
file = fopen(argv[1], "r");
|
||||
if (file) {
|
||||
len = fread(buf, 1, 1460, file);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
for (i=0; i<1; i++) {
|
||||
#else
|
||||
while (__AFL_LOOP(1000)) {
|
||||
memset(buf, 0, 1460);
|
||||
size_t len = read(0, buf, 1460);
|
||||
mdns_query(mdns, "_afpovertcp", "_tcp", 0);
|
||||
mdns_parse_packet(mdns, buf, len);
|
||||
mdns_query_end(mdns);
|
||||
#endif
|
||||
mypbuf.payload = buf;
|
||||
mypbuf.len = len;
|
||||
g_packet.pb = &mypbuf;
|
||||
mdns_test_query("_afpovertcp", "_tcp");
|
||||
mdns_parse_packet(&g_packet);
|
||||
}
|
||||
ForceTaskDelete();
|
||||
mdns_free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user