Communicating between subnets with ESP8266 wifi extender - esp8266

I have a local (household 192.168.0.X) network provided by my router/modem which assigns local IP addresses by the usual Dynamic DNS. I have added an ESP8266 runnning in the WiFi Nat (natp) mode to act as an extender. So it connected to the router as a station and then provides an access point that other devices can connect to. Currently, its subnet is 172...X).
This works in the sense that devices on the extended subnet can see the "world" like google.com etc...
The problem is devices on the 192. network can't see any devices on the extended network.
The source of the problem is pretty obvious: the 192 network devices are all connected by the router which has no clue about any devices connnected to the extender access point.
Is this possible and is there a good ESP 82666 example for this?
If not example, I'm unsure what I'm not understanding-- I'm unsure of what to call this configuration so googling it isn't working.
I feel like there ought to be a way to make the extender just a transparent replicator/relay so the Router is seeing every device and is doing the DHCPS job itself rather than the ESP8266 access point. But I'm stuck.
What sort of configuration approach I can use to expose the devices on the extended network to the computers on the 192 network?
There's a myriad of possible settings but I can't seem to find a permutation that works. (e.g. the Gateway setting or turning off DHCP on the extender access point.) I've tried making the extender network be the same 192.168.0.X rather than 172. But that didn't help.
Detail:
What I have here is a sensor network out in my barn that lives on the access point. I want to be able to access the sensors from inside the house. I've goofed around with workarounds of having the barn devices send their data to a server out in the world. But I want direct access so I can query the devices or do over the air programming directly to the devices from my home computer. I can only do this right now by connecting the home computer to the (slower) extended network access point rather than the high speed home router.
Here's an example of the code I'm modifying (basically one of the ESPWIFI example sketches.)
// NAPT example released to public domain
#if LWIP_FEATURES && !LWIP_IPV6
#define HAVE_NETDUMP 0
#ifndef STASSID
#define STASSID "HouseModem"
#define STAPSK "HouseModemPassword"
#endif
#include <ESP8266WiFi.h>
#include <lwip/napt.h>
#include <lwip/dns.h>
#include <dhcpserver.h>
#define NAPT 1000
#define NAPT_PORT 10
#if HAVE_NETDUMP
#include <NetDump.h>
void dump(int netif_idx, const char* data, size_t len, int out, int success) {
(void)success; // What does this do?
Serial.print(out ? F("out ") : F(" in "));
Serial.printf("%d ", netif_idx);
// optional filter example: if (netDump_is_ARP(data))
{
netDump(Serial, data, len);
//netDumpHex(Serial, data, len);
}
}
#endif
void setup() {
Serial.begin(115200);
Serial.printf("\n\nNAPT Range extender\n");
Serial.printf("Heap on start: %d\n", ESP.getFreeHeap());
#if HAVE_NETDUMP
phy_capture = dump;
#endif
// first, connect to STA so we can get a proper local DNS server
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(500);
}
Serial.printf("\nSTA: %s (dns: %s / %s)\n",
WiFi.localIP().toString().c_str(),
WiFi.dnsIP(0).toString().c_str(),
WiFi.dnsIP(1).toString().c_str());
// give DNS servers to AP side
dhcps_set_dns(0, WiFi.dnsIP(0));
dhcps_set_dns(1, WiFi.dnsIP(1));
WiFi.softAPConfig( // enable AP, with android-compatible google domain
// IPAddress(172, 217, 28, 254),
// IPAddress(172, 217, 28, 254),
// IPAddress(255, 255, 255, 0));
WiFi.localIP(),IPAddress(192,168,0,1),IPAddress(255, 255, 255, 0));
WiFi.softAP(STASSID "extender", STAPSK); // odd way to concat strings
Serial.printf("AP: %s\n", WiFi.softAPIP().toString().c_str());
Serial.printf("Heap before: %d\n", ESP.getFreeHeap());
err_t ret = ip_napt_init(NAPT, NAPT_PORT);
Serial.printf("ip_napt_init(%d,%d): ret=%d (OK=%d)\n", NAPT, NAPT_PORT, (int)ret, (int)ERR_OK);
if (ret == ERR_OK) {
ret = ip_napt_enable_no(SOFTAP_IF, 1);
Serial.printf("ip_napt_enable_no(SOFTAP_IF): ret=%d (OK=%d)\n", (int)ret, (int)ERR_OK);
if (ret == ERR_OK) {
Serial.printf("WiFi Network '%s' with same password is now NATed behind '%s'\n", STASSID "extender", STASSID);
}
}
Serial.printf("Heap after napt init: %d\n", ESP.getFreeHeap());
if (ret != ERR_OK) {
Serial.printf("NAPT initialization failed\n");
}
}
#else
void setup() {
Serial.begin(115200);
Serial.printf("\n\nNAPT not supported in this configuration\n");
}
#endif
void loop() {
}

You can subnetting the routers network from nat devices onwords. So tree like network structure may form.
Let say your router is assigning 192.168.0.x/24 ip to your first hop devices then those devices could modify their access points network with 192.168.1.x/24 and so on upto the possible last hop.
To make it form dynamically on their own you may need to assign common ssid and password to all devices in that structure.
If you could able to achieve this then their may be chances of accessing individual devices from router.
Also you may get the idea of to what hop level individual device seats in network tree by their subnet ip.

Related

Dropping only UDP packets in RPL

1)I am trying to drop only UDP packets in RPL in Contigi-ng OS.
I modified the code in/contiki/core/net/tcpip.c as:
...
static void
packet_input(void)
{
#if DEST_PORT_IS_MAL_DROP
if ((UIP_IP_BUF->proto == UIP_PROTO_UDP) &&
(uip_ntohs(UIP_UDP_BUF->destport)==UDP_MALICIOUS_PORT)){
uip_len=0;}
#endif
#if UIP_CONF_IP_FORWARD
if(uip_len > 0){
...
This drops all packets whose destport = UDP_MALICIOUS_PORT and do not know how to drop only UDP packets and allow control messages.
Thanks in advance
You should change uip6.c in the "os/net/ipv6/uip6.c" path.
please see this paper :A Reference Implementation for RPL Attacks Using Contiki-NG and COOJA.
This is good reference for implementing attacks in Contiki-ng.

How to work with the output of another ECU

I am new in CAPL (CANoe). I have 2 Nodes here; CAN_Portscanner that scans a vehicle and returns 47 ECUs and their services and a Diagnostic Tester that i want to develop. it has to recognize only a few ECUs from the Portscanner. When I find the service, I need to send a service request to an ECU and extend the ECU function with a response in CANoe to know that my request was successful.
I need to read a message from another .can file and work with it.
I tried something like this:
includes
{
#include "CAN_Portscanner.can"
}
variables
{
int counter;
}
void MainTest()
{
while(diagnose_request_msg.ID <= 0x7E1)
{
counter++;
}
write("Number of ECUs in the Tester: %d",counter);
}
I don't know if the #include is correct and why do i obtain a warning about MainTest.
Warning 2033 at (12,1): Use of function 'MainTest' seems to indicate that this file should be a test module or test unit. Diagnostic Tester.can

RPL Setup with Contiki Simple UDP API and Border Router

I have a seemingly easy but quite specific question. I have three different node types in my network: a client, an aggregator and the border router (rpl-border-router). There should be a unicast connection between one (or multiple) clients and an aggregator. When the aggregator gets messages of some specific type or when some threshold is reached the aggregator forwards some other message to the border router. The example code of unicast-recevier (aggregator) in the simple-udp-rpl folder creates a RPL DAG the following way:
static void create_rpl_dag(uip_ipaddr_t *ipaddr) {
struct uip_ds6_addr *root_if;
root_if = uip_ds6_addr_lookup(ipaddr);
if(root_if != NULL) {
rpl_dag_t *dag;
uip_ipaddr_t prefix;
rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr);
dag = rpl_get_any_dag();
uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &prefix, 64);
PRINTF("created a new RPL dag\n");
} else {
PRINTF("failed to create a new RPL DAG\n");
}
}
However, since the border router creates a RPL DAG on its own, the receiver (aggregator) cannot send messages to the border router. But removing this RPL code from the receiver results in the inability to receive messages from the sender (client). So the problem is probably somehow connected to RPL. The ContikiRPL code is not really well documented and I am struggling to make progress. Any help is greatly appreciated.

NSNetService Resolve ipv6 that can not make an http request on it

Recently, i was facing a problem while resolving NSNetService.
I was published an NSNetService with type _http._tcp., to be just like an http server.
Other wise, on another device, i was start searching for this service, and it will find it.
After finding it, i was apply resolveWithTimeout on it.
While resolving, sometimes i was get only ipv6, that i can't make an HTTPRequest using NSURLConnection sendAsynchronousRequest: queue: completionHandler: on it.
How can i apply and HTTPRequest on url contains ipv6 ?
How can i deal with that problem ?
It looks like you're building a string like http://{IP}:{port}/ based on the information provided in NSNetService. And it works fine for an IPv4 address, the resulting string is like http://192.168.1.8:8080/.
However, IPv6 addresses use colons as a separator (instead of periods), so the same code generates a string like http://fe80::e31:db5a:0089:98ba:8080/, and the resulting address is incorrect. First, you need to wrap the address in square brackets: http://[fe80::e31:db5a:0089:98ba]:8080/. Second, fe80::/64 (as in the example) addresses are link-local and can be assigned to each IPv6-supporting interface, so you need to also provide the interface to use, e.g. http://[fe80::e31:db5a:0089:98ba%25en0]:8080/ where %25 is an encoded percent symbol and en0 is the interface name to use.
To sum up, you need to build different strings for IPv4 and IPv6 addresses. Speaking of which, there are Apple's recommendations:
As a rule, you should not resolve a service to an IP address and port number unless you are doing something very unusual.
– Connecting to a Bonjour Service by IP Address
Try to use this URL string if possible: http://{hostname}:{port}/, you won't need those extra IP address manipulations.
So this is what I end up using... it correctly translates address into URL including the interface:
NSString * result = nil;
char host[NI_MAXHOST];
char service[NI_MAXSERV];
int err;
err = getnameinfo(address.bytes, (socklen_t) address.length, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV);
if (err == 0) {
struct sockaddr_storage *sockaddr = (struct sockaddr_storage *)address.bytes;
if (sockaddr->ss_family == AF_INET6) {
result = [NSString stringWithFormat:#"[%s]:%s", host, service];
} else if (sockaddr->ss_family == AF_INET) {
result = [NSString stringWithFormat:#"%s:%s", host, service];
}
}

Erlang C node related question

In the tutorial provided at:
http://www.erlang.org/doc/tutorial/cnode.html
There is the following example:
/* cnode_s.c */
#include
#include
#include
#include
#include "erl_interface.h"
#include "ei.h"
#define BUFSIZE 1000
int main(int argc, char **argv) {
int port; /* Listen port number */
int listen; /* Listen socket */
int fd; /* fd to Erlang node */
ErlConnect conn; /* Connection data */
int loop = 1; /* Loop flag */
int got; /* Result of receive */
unsigned char buf[BUFSIZE]; /* Buffer for incoming message */
ErlMessage emsg; /* Incoming message */
ETERM *fromp, *tuplep, *fnp, *argp, *resp;
int res;
port = atoi(argv[1]);
erl_init(NULL, 0);
if (erl_connect_init(1, "secretcookie", 0) == -1)
erl_err_quit("erl_connect_init");
/* Make a listen socket */
if ((listen = my_listen(port))
I suspect that erl_receive_msg is a blocking call, and I don't know how to overcome this. In C network programming there is the "select" statement but in the Erlang EI API I don't know whether there is such a statement.
Basically I want to build a C node, that continuously sends messages to Erlang nodes. For simplicity suppose there is only one Erlang node.
The Erlang node has to process the messages it receives from the C node. The Erlang node is not supposed to ensure that it has received the message, not does it have to reply with the result of processing. Therefore once the message is sent I don't care about it faith.
One might think that one could modify the code as:
...
if (emsg.type == ERL_REG_SEND) {
...
while(1) {
//generate tuple
erl_send(fd, fromp, tuple);
//free alloc resources
}
...
}
This will produce an infinite loop in which we produce and consume (send) messages.
But there is an important problem: if I do this, then the C node might send too many messages to the Erlang node (so there should be a way to send a message from the Erlang node to the C node to slow down), or the Erlang node might think that the C node is down.
I know that the questions must be short an suite (this is long and ugly), but summing up:
What mechanism (procedure call, algorithm) one might use to develop an eager producer in C for a lazy consumer in Erlang, such that both parties are aware of the underlying context ?
I use Port Drivers myself for the case you are describing (haven't touched the C nodes because I'd rather have more decoupling).
Have a look at the Port Driver library for Erlang: EPAPI. There is a project that leverages this library: Erland DBus.
Did you check the ei_receive_msg_tmo function? I suppose it works similar to the receive after construct of Erlang, so if you set timeout to 0, it will be non-blocking.
I believe erl_interface is deprecated, and ei should be used instead. This might be a complete misinformation though...
you need to take a closer look at the tutorial link that you posted. (search for "And finally we have the code for the C node client.") You will see that the author provided a client cnode implementation. It looks rational.

Resources