Commit 3a5e5f10 authored by Philip Gladstone's avatar Philip Gladstone
Browse files

Take 2: Add regular sends to mdns. Check for (some) buffer overflows. Make it handle unicast

Merging as suggested by @TerryE (and squashing at the same time. Turns out that this feature is enabled for this repo).

* Squashed commit of the following:

commit f985f10d9d2ee035f5a6ee6245c60d9904d98cc1
Author: philip <philip@gladstonefamily.net>
Date:   Sun Mar 27 21:52:46 2016 -0400

    Better mdns code

commit 6ee49ee106274bc63f6309047e57f7bc9828523e
Author: philip <philip@gladstonefamily.net>
Date:   Fri Mar 25 23:25:11 2016 -0400

    Update the docs

commit 7e455541c6f2531824cfb2419d051f1306935fdf
Author: philip <philip@gladstonefamily.net>
Date:   Thu Mar 24 21:58:16 2016 -0400

    Add retries and buffer checking to mdns

    Get the length right

    Now it seems to work

* Might work for combined mode

* Fix crash

* Simplified various bits of code. Changed the LUA interface

Added checking (to some degree) incoming quyery types

Move the defaults to the right place

Added reference to the RFC`
parent eccb2e4a
...@@ -41,6 +41,7 @@ SUBDIRS= \ ...@@ -41,6 +41,7 @@ SUBDIRS= \
crypto \ crypto \
dhtlib \ dhtlib \
tsl2561 \ tsl2561 \
net \
http http
endif # } PDIR endif # } PDIR
...@@ -86,6 +87,7 @@ COMPONENTS_eagle.app.v6 = \ ...@@ -86,6 +87,7 @@ COMPONENTS_eagle.app.v6 = \
dhtlib/libdhtlib.a \ dhtlib/libdhtlib.a \
tsl2561/tsl2561lib.a \ tsl2561/tsl2561lib.a \
http/libhttp.a \ http/libhttp.a \
net/libnodemcu_net.a \
modules/libmodules.a \ modules/libmodules.a \
# Inspect the modules library and work out which modules need to be linked. # Inspect the modules library and work out which modules need to be linked.
......
#ifndef _NODEMCU_MDNS_H
#define _NODEMCU_MDNS_H
struct nodemcu_mdns_info {
const char *host_name;
const char *host_desc;
const char *service_name;
uint16 service_port;
const char *txt_data[10];
};
void nodemcu_mdns_close(void);
bool nodemcu_mdns_init(struct nodemcu_mdns_info *);
#endif
#include "c_string.h" #include "c_string.h"
#include "c_stdlib.h"
// const char *c_strstr(const char * __s1, const char * __s2){ // const char *c_strstr(const char * __s1, const char * __s2){
// } // }
...@@ -14,3 +15,115 @@ ...@@ -14,3 +15,115 @@
// int c_strcoll(const char * s1, const char * s2){ // int c_strcoll(const char * s1, const char * s2){
// } // }
//
char *c_strdup(const char *c) {
int len = os_strlen(c) + 1;
char *ret = os_malloc(len);
if (ret) {
memcpy(ret, c, len);
}
return ret;
}
/* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
c_strlcpy(char *dst, const char *src, size_t siz)
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
/* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
c_strlcat(char *dst, const char *src, size_t siz)
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
...@@ -39,5 +39,11 @@ ...@@ -39,5 +39,11 @@
// size_t c_strcspn(const char * s1, const char * s2); // size_t c_strcspn(const char * s1, const char * s2);
// const char *c_strpbrk(const char * /*s1*/, const char * /*s2*/); // const char *c_strpbrk(const char * /*s1*/, const char * /*s2*/);
// int c_strcoll(const char * /*s1*/, const char * /*s2*/); // int c_strcoll(const char * /*s1*/, const char * /*s2*/);
//
extern size_t c_strlcpy(char *dst, const char *src, size_t siz);
extern size_t c_strlcat(char *dst, const char *src, size_t siz);
extern char *c_strdup(const char *src);
#endif /* _C_STRING_H_ */ #endif /* _C_STRING_H_ */
// Module for access to the espconn_mdns functions // Module for access to the nodemcu_mdns functions
#include "module.h" #include "module.h"
#include "lauxlib.h" #include "lauxlib.h"
...@@ -9,115 +9,59 @@ ...@@ -9,115 +9,59 @@
#include "c_types.h" #include "c_types.h"
#include "mem.h" #include "mem.h"
#include "lwip/ip_addr.h" #include "lwip/ip_addr.h"
#include "espconn.h" #include "nodemcu_mdns.h"
#include "user_interface.h" #include "user_interface.h"
typedef struct wrapper {
struct mdns_info mdns_info;
char data;
} wrapper_t;
static wrapper_t *info;
typedef enum phase {
PHASE_CALCULATE_LENGTH,
PHASE_COPY_DATA
} phase_t;
static char *advance_over_string(char *s)
{
while (*s++) {
}
// s now points after the null
return s;
}
// //
// mdns.close() // mdns.close()
// //
static int mdns_close(lua_State *L) static int mdns_close(lua_State *L)
{ {
if (info) { nodemcu_mdns_close();
espconn_mdns_close();
c_free(info);
info = NULL;
}
return 0; return 0;
} }
//
// this handles all the arguments. Two passes are necessary --
// one to calculate the size of the block, and the other to
// copy the data. It is vitally important that these two
// passes are kept in step.
// //
static wrapper_t *process_args(lua_State *L, phase_t phase, size_t *sizep) // mdns.register(hostname [, { attributes} ])
//
static int mdns_register(lua_State *L)
{ {
wrapper_t *result = NULL; struct nodemcu_mdns_info info;
char *p = NULL;
if (phase == PHASE_COPY_DATA) { memset(&info, 0, sizeof(info));
result = (wrapper_t *) c_zalloc(sizeof(wrapper_t) + *sizep);
if (!result) { info.host_name = luaL_checkstring(L, 1);
return NULL; info.service_name = "http";
} info.service_port = 80;
p = &result->data; info.host_desc = info.host_name;
}
if (phase == PHASE_CALCULATE_LENGTH) {
luaL_checktype(L, 1, LUA_TSTRING);
luaL_checktype(L, 2, LUA_TSTRING);
(void) luaL_checkinteger(L, 3);
*sizep += c_strlen(luaL_checkstring(L, 1)) + 1;
*sizep += c_strlen(luaL_checkstring(L, 2)) + 1;
} else {
c_strcpy(p, luaL_checkstring(L, 1));
result->mdns_info.host_name = p;
p = advance_over_string(p);
c_strcpy(p, luaL_checkstring(L, 2));
result->mdns_info.server_name = p;
p = advance_over_string(p);
result->mdns_info.server_port = luaL_checkinteger(L, 3);
}
if (lua_gettop(L) >= 4) { if (lua_gettop(L) >= 2) {
luaL_checktype(L, 4, LUA_TTABLE); luaL_checktype(L, 2, LUA_TTABLE);
lua_pushnil(L); // first key lua_pushnil(L); // first key
int slot = 0; int slot = 0;
while (lua_next(L, 4) != 0 && slot < sizeof(result->mdns_info.txt_data) / sizeof(result->mdns_info.txt_data[0])) { while (lua_next(L, 2) != 0 && slot < sizeof(info.txt_data) / sizeof(info.txt_data[0])) {
if (phase == PHASE_CALCULATE_LENGTH) { luaL_checktype(L, -2, LUA_TSTRING);
luaL_checktype(L, -2, LUA_TSTRING); const char *key = luaL_checkstring(L, -2);
*sizep += c_strlen(luaL_checkstring(L, -2)) + 1;
*sizep += c_strlen(luaL_checkstring(L, -1)) + 1; if (c_strcmp(key, "port") == 0) {
info.service_port = luaL_checknumber(L, -1);
} else if (c_strcmp(key, "service") == 0) {
info.service_name = luaL_checkstring(L, -1);
} else if (c_strcmp(key, "description") == 0) {
info.host_desc = luaL_checkstring(L, -1);
} else { } else {
// put in the key int len = c_strlen(key) + 1;
c_strcpy(p, luaL_checkstring(L, -2));
result->mdns_info.txt_data[slot] = p;
p = advance_over_string(p);
// now smash in the value
const char *value = luaL_checkstring(L, -1); const char *value = luaL_checkstring(L, -1);
p[-1] = '='; char *p = alloca(len + c_strlen(value) + 1);
c_strcpy(p, value); strcpy(p, key);
p = advance_over_string(p); strcat(p, "=");
strcat(p, value);
info.txt_data[slot++] = p;
} }
lua_pop(L, 1); lua_pop(L, 1);
} }
} }
return result;
}
//
// mdns.register(hostname, servicename, port [, attributes])
//
static int mdns_register(lua_State *L)
{
size_t len = 0;
(void) process_args(L, PHASE_CALCULATE_LENGTH, &len);
struct ip_info ipconfig; struct ip_info ipconfig;
...@@ -127,25 +71,18 @@ static int mdns_register(lua_State *L) ...@@ -127,25 +71,18 @@ static int mdns_register(lua_State *L)
return luaL_error(L, "No network connection"); return luaL_error(L, "No network connection");
} }
wrapper_t *result = process_args(L, PHASE_COPY_DATA, &len);
if (!result) {
return luaL_error( L, "failed to allocate info block" );
}
result->mdns_info.ipAddr = ipconfig.ip.addr;
// Close up the old session (if any). This cannot fail // Close up the old session (if any). This cannot fail
// so no chance of losing the memory in 'result' // so no chance of losing the memory in 'result'
mdns_close(L); mdns_close(L);
// Save the result as it appears that espconn_mdns_init needs // Save the result as it appears that nodemcu_mdns_init needs
// to have the data valid while it is running. // to have the data valid while it is running.
info = result; if (!nodemcu_mdns_init(&info)) {
mdns_close(L);
espconn_mdns_init(&(info->mdns_info)); return luaL_error(L, "Unable to start mDns daemon");
}
return 0; return 0;
} }
......
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libnodemcu_net.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
INCLUDES := $(INCLUDES) -I $(PDIR)include
INCLUDES += -I ./
INCLUDES += -I ../libc
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile
This diff is collapsed.
...@@ -9,13 +9,21 @@ ...@@ -9,13 +9,21 @@
Register a hostname and start the mDNS service. If the service is already running, then it will be restarted with the new parameters. Register a hostname and start the mDNS service. If the service is already running, then it will be restarted with the new parameters.
#### Syntax #### Syntax
`mdns.register(hostname, servicename, port [, attributes])` `mdns.register(hostname [, attributes])`
#### Parameters #### Parameters
- `hostname` The hostname for this device. Alphanumeric characters are best. - `hostname` The hostname for this device. Alphanumeric characters are best.
- `servicename` The service name for this device. Alphanumeric characters are best. This will get prefixed with `_` and suffixed with `._tcp` - `attributes` A optional table of options. The keys must all be strings.
- `port` The port number for the primary service.
- `attributes` A optional table of up to 10 attributes to be exposed. The keys must all be strings. The `attributes` contains two sorts of attributes -- those with specific names, and those that are service specific. [RFC 6763](https://tools.ietf.org/html/rfc6763#page-13}
defines how extra, service specific, attributes are encoded into the DNS. One example is that if the device supports printing, then the queue name can
be specified as an additional attribute. This module supports up to 10 such attributes.
The specific names are:
- `port` The port number for the service. Default value is 80.
- `service` The name of the service. Default value is 'http'.
- `dscription` A short phrase (under 63 characters) describing the service. Default is the hostname.
#### Returns #### Returns
`nil` `nil`
...@@ -25,10 +33,12 @@ Various errors can be generated during argument validation. The NodeMCU must hav ...@@ -25,10 +33,12 @@ Various errors can be generated during argument validation. The NodeMCU must hav
#### Example #### Example
mdns.register("fishtank", "http", 80, { hardware='NodeMCU'}) mdns.register("fishtank", {hardware='NodeMCU'})
Using `dns-sd` on OS X, you can see `fishtank.local` as providing the `_http._tcp` service. You can also browse directly to `fishtank.local`. In Safari you can get all the mDNS web pages as part of your bookmarks menu. Using `dns-sd` on OS X, you can see `fishtank.local` as providing the `_http._tcp` service. You can also browse directly to `fishtank.local`. In Safari you can get all the mDNS web pages as part of your bookmarks menu.
mdns.register("fishtank", { description="Top Fishtank", service="http", port=80, location='Living Room' })
## mdns.close() ## mdns.close()
Shut down the mDNS service. This is not normally needed. Shut down the mDNS service. This is not normally needed.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment