Compare IP's

Hi,

I’m a bit lost, so I will post my code then try to explain what I’m trying to do.

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

SdFat SD;

EthernetClient client;
EthernetServer server(80);
unsigned long lastMillis;
byte mac[] = {0xxx, 0xxx, 0xxx, 0xxx, 0xxx, 0xxx}; // Arduino mac adress
IPAddress IP;
IPAddress lastIP;

void setup() {
  Serial.begin(9600);
  if (!SD.begin(4)) {
    return;
  }
  Serial.println(F("Initializing Arduino"));
  if (Ethernet.begin(mac) == 0) {
    while(1);
  }
  delay(1000);
  server.begin();
  NoIP();
}
void loop() {
  if (millis() - lastMillis >= 36000000) {
    NoIP();
  }
}
void NoIP() {
  const char checkIPserver[] = "checkip.dyndns.org";
  const char noIPserver[] = "dynupdate.no-ip.com";
  const int webIP_BUF_SZ = 50;
  int webIP_index = 0;
  char webIP[webIP_BUF_SZ];
  if (client.connect(checkIPserver, 80)) {
    client.println("GET / HTTP/1.0");
    client.println();
  } 
  while (client.connected()) { 
    while (client.available()) {
      char character = client.read();
      Serial.write(character);
      if (webIP_index < (webIP_BUF_SZ - 1)) {
        webIP[webIP_BUF_SZ] = character;
        webIP_index++;
      }
    }
  }
  client.stop();
  (strstr(webIP, "Address: "));
  (strstr(webIP, "</body>"))[0] = 0;
  for(int i = 0; i < 16; i++) {
    IP[i] = (byte)webIP[i];
  }
  Serial.println(IP);
  if (lastIP != IP) {
    if (client.connect(noIPserver, 80) == 1)  {
      Serial.println("Connected to no-ip");
      client.println("GET /nic/update?hostname=xxx HTTP/1.0");
      client.println("Host: dynupdate.no-ip.com");
      client.println("Authorization: Basic xxxx");
      client.println("User-Agent: Arduino 1.0");
      client.println();
      while (client.connected()) { 
        while (client.available()) {
          char character = client.read();
          Serial.write(character);
        }
      }
      client.stop();
      lastMillis = millis();
      lastIP = IP;
    }
  }
}

Ok, I’m trying to do a IP check once every hour by geting the IP from checkip.dyndns.org, that returns the following response:

<html><head><title>Current IP Check</title></head><body>Current IP Address: 175.136.194.173</body></html>

Then I want to compare it to the lastIP stored (later on I plan to store the last one to the EEPROM), and if it has change send an update package to NO-IP.

As ever, I’m having trouble with the pointers and comparrision part…

  (strstr(webIP, "Address: "));
  (strstr(webIP, "</body>"))[0] = 0;
  for(int i = 0; i < 16; i++) {
    IP[i] = (byte)webIP[i];
  }
  Serial.println(IP);
  if (lastIP != IP)

The first part (I think it’s ok, but) I don’t know exactly how to check it since the Serial.println(IP) prints numbers in the IP form like “xxx.xx.xxx.xx” but it don’t correspond to my real IP (from the checkIP response), and after that I don’t know how to compare it with the lastIP stored.

I’m sorry, I know its probably a beginner’s question, maybe even stupid, but I couldn’t solve it alone, if anyone can help it will be much apreciated.

  (strstr(webIP, "Address: "));

strstr() returns a value. You throw it away. This call accomplishes nothing.

  (strstr(webIP, "</body>"))[0] = 0;

This makes sense only after some study. You should document why it works, so one does not have to study the code to determine why.

  for(int i = 0; i < 16; i++) {
    IP[i] = (byte)webIP[i];
  }

This does not make sense. You know the length of webIP. Use that length, rather than assuming that the length is 16.

Also, IPAddress (which IP is an instance of) is a class. It is NOT a 16 byte array. It overloads the operator, but the range of indexes is 0 to 3, NOT 0 to 16. Each value that you get or set is a byte, NOT a character.

You are going to need to parse the webIP string, finding the dots, and convert each token to an int, to store in IP. strtok() and atoi() are in your future.

The "internal representation" of an IP address is normally a 32bit unsigned integer ("unsigned long" works on Arduino.) To compare two IP addresses, they both need to be represented in the same fashion; C doesn't do automatic conversions (something like "if (10 == "10")" will always be false.) So you can either parse the text IP address into an integer, and then use a numeric compare, or you can reformat your numeric IP address into a string, and then do a string compare (which is less reliable, because leading zeros and such.)

If you're getting the address from checkip.dyndns.org, This will be the internet facing interface of your router. Attempting to use it internally on your LAN will cause you headaches.

@PaulS thanks!

(strstr(webIP, "Address: "));

strstr() returns a value. You throw it away. This call accomplishes nothing.

I’m confused, I use it in another part or my code and it works as I expected it to work here.

   char POST = command=Kitchen&value=1;
    char *command = (strstr(POST, "=") + 1);
    char *value = (strstr(command, "=") + 1);
    (strstr(command, "&"))[0] = 0;

Returns Kitchen / 1… :cold_sweat:

(strstr(webIP, "</body>"))[0] = 0;

This makes sense only after some study. You should document why it works, so one does not have to study the code to determine why.

I use it to “remove” the end of the char array, and it seen to work.

You are going to need to parse the webIP string, finding the dots, and convert each token to an int, to store in IP. strtok() and atoi() are in your future.

Ok, I’m trying to do this, but still having some trouble.

void setup(){
  Serial.begin(9600);
  Serial.println("Initializing");
}
void loop (){
  unsigned long *IP;
  char webIP[] = "<html><head><title>Current IP Check</title></head><body>Current IP Address: 175.185.195.174</body></html>";
  strstr(webIP, "</body>")[0] = 0; // remove the useless ending part of the array
  char *token = webIP + 76; // remove the useless begining part of the array
  token = strtok (token, ".");
  for (int i = 0; token != 0; i++) {
    IP[i] = atoi(token);
    Serial.print(IP[i]);
    Serial.print(".");
    token = strtok (0, ".");
  }
  delay(5000);
}
Initializing
175.185.195.174.

It this? Am I on the right way? I don’t know how to remove the useless begining part of the array “randomly”. Can someone advice me?

@westfw thanks, I will try with the integer comparison as you suggested.

@KenF thanks, yes I know that this returns the External IP, but I want to use it to update the Dynamic DNS, so it need to use external IP.

 (strstr(webIP, "Address: "));

What variable will the position of Address: in the variable WebIP be assigned to ?

Arank:
@KenF thanks, yes I know that this returns the External IP, but I want to use it to update the Dynamic DNS, so it need to use external IP.

Aha! that makes perfect sense then.

UKHeliBob:

 (strstr(webIP, "Address: "));

What variable will the position of Address: in the variable WebIP be assigned to ?

@UKHeliBob Oh, thanks.

void setup(){
  Serial.begin(9600);
  Serial.println("Initializing");
}
void loop (){
  unsigned long *IP;
  char webIP[] = "<html><head><title>Current IP Check</title></head><body>Current IP Address: 175.185.195.174</body></html>";
  strstr(webIP, "</body>")[0] = 0; // remove the useless ending part of the array
  char *token = (strstr(webIP, "Address:") + 9);
  token = strtok (token, ".");
  for (int i = 0; token != 0; i++) {
    IP[i] = atoi(token);
    Serial.print(IP[i]);
    Serial.print(".");
    token = strtok (0, ".");
  }
  delay(5000);
}
Initializing
175.185.195.174.

I think it’s working now, I will do more tests when I get home using the appropriatted IPAddress variable instead the unsigned long (used just for test purposes).

  unsigned long *IP;

This is a pointer. Where does it point to? Can you REALLY write to where it points to?

    IP[i] = atoi(token);

You try to, but it is VERY unlikely that you can write there.

There are 4 octets in an IP address (or 6 at most). You really SHOULD be defining an array NOT a pointer.

PaulS:

  unsigned long *IP;

This is a pointer. Where does it point to? Can you REALLY write to where it points to?

    IP[i] = atoi(token);

You try to, but it is VERY unlikely that you can write there.

There are 4 octets in an IP address (or 6 at most). You really SHOULD be defining an array NOT a pointer.

@PaulS thanks.
I was using that just for test purposes, because I was on work testing it on http://123d.circuits.io/.

Already changed it for IPAddress when I got home, made some silly changes and it works like a charm now.

void NoIP() {
  const int webIP_BUF_SZ = 25;
  const int IPaddress_BUF_SZ = 10;
  int webIP_index = 0;
  int IPaddress_index = 0;
  char webIP[webIP_BUF_SZ] = {0};
  const char IPaddress[IPaddress_BUF_SZ] = "Address: ";
  const char checkIPserver[] = "checkip.dyndns.org";
  const char noIPserver[] = "dynupdate.no-ip.com";
  if (client.connect(checkIPserver, 80)) {
    client.println("GET / HTTP/1.0");
    client.println();
  }
  while (client.connected()) {
    if (client.available()) {
      char character = client.read();
      if (character == IPaddress[IPaddress_index]) {
        IPaddress_index++;
      }
      else if (0 < IPaddress_index > IPaddress_BUF_SZ - 1 && character != IPaddress[IPaddress_index]) {
        IPaddress_index = 0;
      }
      if (IPaddress_index >= IPaddress_BUF_SZ - 1) {
        if (webIP_index < (webIP_BUF_SZ - 1)) {
          webIP[webIP_index] = character;
          webIP_index++;
        }
      }
    }
  }
  IPaddress_index = 0;
  client.stop();
  strstr(webIP, "</body>")[0] = 0;
  char *token = webIP;
  token = strtok (token, ".");
  for (int i = 0; token != 0; i++) {
    IP[i] = atoi(token);
    token = strtok (0, ".");
  }
  if (IP != lastIP) {
    if (client.connect(noIPserver, 80)) {
      client.println("GET /nic/update?hostname=xxxx HTTP/1.0");
      client.println("Host: dynupdate.no-ip.com");
      client.println("Authorization: Basic xxxxx");
      client.println("User-Agent: Arduino 1.0");
      client.println();
      client.stop();
      lastMillis = millis();
      lastIP = IP;
    }
  }
}
      else if (0 < IPaddress_index > IPaddress_BUF_SZ - 1 && character != IPaddress[IPaddress_index]) {

The WTF light exploded.

This is NOT testing that IPaddress_index is between 0 and IPaddress_BUF_SZ - 1.

made some silly changes and it works like a charm now.

Making some serious changes will eliminate the bug that hasn’t bitten you in the ass yet (but is waiting to).

and if it has change send an update package to NO-IP.

Instead of spending time seeing if the IP address has changed, just assume it has and send an update to no-ip.com.