Problem with Arduino+EthernetShield and NAT

Hi all, I'm using an Arduino Uno with the Arduino Ethernet Shield. If I set an IP like 192.168.0.x and connect the board to an ADSL router, the Arduino sends the HTTP request and the server sends related HTTP response (I see it on the remote server log). But the Arduino receives nothing or some illegible characters. The ADSL router has not antivirus running and the DHCP is disabled.

I have the same problem using 3 different kinds of ADSL routers placed in 3 cities or using Arduino Diecimila or the last version of the Arduino Ethernet Shield.

In 2 cases the Arduino receives fine: - when I set a public IP and connect the board directly to the net. In the sketch, I change only the IP. - when I set a NAT IP and use a PC for routing (connect the Ethernet shield to a PC and the PC re-address the boards packages on a WiFi connection). The sketch is the same of using ADSL router.

I suppose it is a problem related to the packages creation on Arduino and so to the Ethernet library .... Packages could not be fully compatible with the routers I used and when the routers receives the HTTP response they don't know how re-address and delivery the packages to the 192.168.0.x. What do you think? Any help on the "connection to ADSL" problem?

Regards!

The Wiznet ethernet shield has no problems with NAT or routing. I use a Mega/Ethernet shield behind 3 routers as a test. Two of the routers just forward, but the third (routerA) does a NAT to a public ip.

Arduino -> ether1 routerC wlan1 -> wlan1 routerB ether1 -> ether2 routerA ether1 -> cablemodem/public ip

Edit: I use Mikrotik routers. Those are all different models. What brand and model router are you using? Check your network and routing settings in the router.

SurferTim, thanks for your response. Could you post a link with the image of the Wiznet ethernet shield? Just to be sure, googling I found some different boards. I'm using a Arduino Ethernet shield (http://arduino.cc/en/uploads/Main/ArduinoEthernetShieldV3.jpg), it has a Wiznet chip on board.

The routers brand is Netgear. Checks done on: firewall disabled, antivirus disabled, DHCP disabled, statically assignment every time of the same IP to the same MAC address. No more ideas on what checking ... :(

It required no additional setting for my shield to work with my routers. It worked just like one of my computers.
I would leave the Netgear router settings default and try it.

The only thing that would mess things up is if you assigned an IP to the shield that the dhcp server in the Netgear router issues. That causes issues. Insure the IP is not being used by another device on that localnet.

My ethenet shield is the Arduino shield.
http://arduino.cc/en/Main/ArduinoEthernetShield

Edit: What does this mean?
“statically assignment every time of the same IP to the same MAC address”

Thanks again.

We have the same shield. IP is not used by other devices and with the default router configuration, it doesn't works.

Sorry for the wrong sentence. I try to explain better. Each time the device with MAC address ABC is connected to the router, it assumes to use a predefined IP for such a device. In my case the predefined IP is the same used to set the Arduino. It was my last test after to disable DHCP.

Regards

OK. Can you ping the Arduino from a computer on the localnet? Can you access the internet from that computer?
If so, please post the network settings from that computer. IP, subnet mask, and gateway.

Yes on both questions.

I use classic configurations: IP 192.168.0.4 - gateway: 192.168.0.1 - mask 255.255.255.0

192.168.0.5 for the Arduino

This works for me to Google. It will kinda outrun your serial port, but you can see if it is working.
BTW, the ip address for Google in the Web Client example is no longer valid.

/*
  Web client
 
 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 created 18 Dec 2009
 by David A. Mellis
 
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,0,5 };
byte server[] = { 74,125,65,99 }; // New Google IP

// Initialize the Ethernet client library
// with the IP address and port of the server 
// that you want to connect to (port 80 is default for HTTP):
Client client(server, 80);

void setup() {
  // start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // start the serial library:
  Serial.begin(9600);
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect()) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /search?q=arduino HTTP/1.0");
    client.println();
  } 
  else {
    // kf you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop()
{
  // if there are incoming bytes available 
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    for(;;)
      ;
  }
}

Edit: Is that computer getting that IP from the dhcp server? Or is it static?
The Netgear localnet dhcp server may “own” 192.168.0.2 to 192.168.0.51. Static ips need to be outside this range.
Check your router in “LAN IP SETUP - Advanced” according to Netgear docs.

If the dhcp server has an active lease on that ip, it doesn’t matter if the device is online or not. That ip is for that mac address only. My router dhcp server has a 3 day lease time. Connect once and get an ip, then immediately disconnect. That ip is not good for any other mac address for three days.

I used that example and it worked. Even if it looks to be done to work every time: no loop requests, GET in 1 row to avoid sending packages each print()|println(). Already tried with several IPs (192.168.0.100 - 150). Router has been reset and reconfigured more times. Problem persists.

Now you could imagine my tired brain doesn't understand why using an ADSL router the sketch doesn't work while it works using a pc like a router.

Thanks again SurferTim!

Regards

That example only runs once. Then it enters an endless loop.

It would be up to you now to modify that code to fit your needs. :)

It has been the starting point to develop the problematic sketch :)

Did you also specify a default gateway with the adress of your router?

http://www.arduino.cc/en/Reference/EthernetBegin

You will need that for the ethernet shield to know where to send stuf which is not on it's own subnet. In the router you will have to do port forwarding for port 80 for nat as well as for a firewall if it's availlable.

If the gateway is xx.xx.xx.1 and the subnet is 255.255.255.0, it is not required in Ethernet.begin(). Those values are set by default.

Thanks for your responses.

Wortelsoft, the sketch doesn't create problems on sending data. Shield sends fine. I checked the server log, it receives and send the waited response. The problem is on receiving server response.

I thought that script worked for you. It did not?

Using a PC like a router? How do you have that set up? Are you using internet connection sharing? And that works ok? But the Arduno does not receive if connected directly to the ADSL modem. Correct?

Add: My cablemodem does not like new devices. If I use a device with a different mac address using the same ip as a previous device, I must power down my cablemodem for several seconds, and then power it up again to get it to work. It has to do with the arp register in the cablemodem. Maybe your ADSL modem is the same.

SurferTim: I thought that script worked for you. It did not?

The WebClient example works.

SurferTim: Using a PC like a router? How do you have that set up? Are you using internet connection sharing? And that works ok? But the Arduno does not receive if connected directly to the ADSL modem. Correct?

Yes. Perfect. It is.

SurferTim: Add: My cablemodem does not like new devices. If I use a device with a different mac address using the same ip as a previous device, I must power down my cablemodem for several seconds, and then power it up again to get it to work. It has to do with the arp register in the cablemodem. Maybe your ADSL modem is the same.

It is a new thing to try. I'll done. Thanks!

The WebClient sketch works connected directly to the ADSL modem?

I forgot to mention one thing. If the ISP issues ips by dhcp, you might have a problem. If the device does not get its ip by dhcp, it may not be able to communicate with the ADSL modem.

Does your computer (the one you use for the connection sharing) get its public ip by dhcp? Or is it a static assignment?

SurferTim: The WebClient sketch works connected directly to the ADSL modem?

Yes, it works. Make it more complex, it doesn't work. For example if you try to move the requests in the loop.

SurferTim: I forgot to mention one thing. If the ISP issues ips by dhcp, you might have a problem. If the device does not get its ip by dhcp, it may not be able to communicate with the ADSL modem.

Does your computer (the one you use for the connection sharing) get its public ip by dhcp? Or is it a static assignment?

That computer doesn't get a public IP, it gets the IP by DHCP from the same ADSL router raising the Ethernet problem (it is also a WiFi router)

This is a little more complex. It does not load the webpage on startup. You press ‘r’ and enter key to load.
You can load multiple times by pressing ‘r’ again. I would pick a webpage that is not so large tho. That Google download is a big one!

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,0,5 };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };

byte server[] = { 74,125,65,99 }; // Google

Client client(server, 80);

void setup() {
  Ethernet.begin(mac, ip, gateway, subnet);
  Serial.begin(9600);
  delay(2000);
  Serial.println("Ready. Press 'r' and enter to load page.");
}

void loop()
{
  if(Serial.available())
  {
    int inByte = Serial.read();
    if( inByte == 'r') getPage();
  }  
}

void getPage()
{
  int inChar;

  Serial.print("connecting...");

  if (client.connect())
  {
    Serial.println("connected");
    client.write("GET / HTTP/1.0\r\n\r\n");
  } 
  else
  {
    Serial.println("failed");
    return;
  }

  while(client.connected())
  {
    while (client.available())
    {
      inChar = client.read();
      Serial.write(inChar);
    }
  }

  Serial.println();
  Serial.println("disconnecting.");
  client.stop();
}

Edit: This new code should be a little more patient about delays.

SurferTim, thanks.
Your sketch and an advice by the Italian forum drove me on the solution. It doesn’t works but with a little change it was fine:
waiting a response for 5 seconds or until a data is available.
I don’t understand because such a problem was done only in case of direct connection on adsl router and not other cases (the pc used like router should be a worse situation …)
Anyway, it’s fixed and energies will be for the next problem :slight_smile:

#include <SPI.h>
#include <Ethernet.h>
#include <Client.h>

byte mac[6] = { 0x90, 0xA2, 0xDA, 0x00, 0x36, 0x01 };
byte ip[4] = { 192, 168, 0, 4 };
const char url[]="/";


byte server[4] = { 74,125,65,99 };
Client client(server, 80);
int i;
int waiting;
char c;

void setup() {
  for(i = 2; i < 10; i++){
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  for(i = 14; i < 20; i++){
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);
  }
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  delay(1000);
}

void loop() {
  if (client.connect()) {
    client.print("GET ");
    client.print(url);
    client.println(" HTTP/1.1");
    client.println();
    Serial.println("           ");
    Serial.println("reading ...");

    waiting = 0;
    while (!client.available() && waiting < 5000){
       delay(1);
        waiting++;
    }

    while (client.available()){
        c = client.read(); 
        Serial.print(c);       
     }
  }
  client.stop();
  delay(1000);
  Ethernet.begin(mac, ip);
}