Pages: [1] 2   Go Down
Author Topic: Detect ip of client?  (Read 1579 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 197
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a Mega 2560 and an Ethernet shield, and basically I'm prototyping an architectural lighting controller for my church that is controlled via a web interface. I would like to be able to have it password protected, I.e. client is presented with a text box and enters password before they are able to control anything. So I would need to be able to identify each client to see if they have logged on already or not. So is there a way to find a clients IP, or individually identify it?
Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 144
Posts: 5977
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a thread that covers what you want.
http://arduino.cc/forum/index.php/topic,135082.0.html
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why not using HTTP authentication and checking the client's password at every request?
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 197
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yea I'm actually one step ahead of you on that. But how do you log the client out?
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Define "log out". Do you want to deny access after some time? If you send the client a 4XX result code it will ask again for the credentials if that's what you want.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 197
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well I had issues with browsers eternally remembering the password and stuff but I fixed it. I have gotten it where it has a list of logins on an SD card with permissions that it compares it to. So all I have to do now is change the page presented and stuff
« Last Edit: February 06, 2013, 09:33:25 am by ematson5897 » Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Usually the browser remembers the credentials during runtime. If you quit the browser, it should forget all credentials the user not explicitly saved (and saving is possible for web forms too).
If you wanna circumvent that, send a random realm, because the browser stores the credentials for one realm and re-ask for them if the realm changes.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 197
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok. Heres my code so far:
Code:
#include <Base64.h>
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>
const byte slots = 20;
IPAddress clientIP[slots];
boolean IPUsed[slots];
boolean passEntered[slots];
int currClient;
boolean newClient;
int loginCount[slots];
char encoded[100];
char decoded[100];
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 6, 3, 2);
File accounts;
const char userHeader[] = "<user>";
const char userFooter[] = "</user>";
char permissions[slots];

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);

void setup()
{
    Serial.begin(115200);    
  pinMode(53, OUTPUT);     // change this to 53 on a mega
  pinMode(10, OUTPUT);     // change this to 53 on a mega
  digitalWrite(10,HIGH);
  Serial.print("Initializing SD card...");
  
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  lcd.begin(16, 2);
  pinMode(8, OUTPUT);    
  Ethernet.begin(mac);
  server.begin();
  
  
    lcd.print("IP:");

  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    lcd.print(Ethernet.localIP()[thisByte], DEC);
    
    if(thisByte != 3)
      lcd.print(".");
  }
}

void loop()
{
  
  EthernetClient client = server.available();
  if (client) {
    IPAddress temp;
    temp = client.remoteIP();
    Serial.println(temp);
    
    boolean matched = false;
    for(int i = 0; i < slots; i++)
    {
        if(temp == clientIP[i])
        {
          Serial.println("returning");
          newClient = false;
          loginCount[i] ++;
          matched = true;
          currClient = i;

        }
    }
    
    if(!matched)
    {
      for(int i = 0; i < slots; i++)
      {
        if(!IPUsed[i])
        {
          Serial.println("new");
          newClient = true;
          loginCount[i] = 0;
          clientIP[i] = temp;
          IPUsed[i] = true;
          currClient = i;
          passEntered[i] = false;
          return;
        }
      }
      
    }
    
    lcd.setCursor(0,1);
    lcd.print('C');
    lcd.print(currClient);
    lcd.print(':');
    lcd.println(clientIP[currClient]);
    boolean currentLineIsBlank = true;
    String buffer = "";  
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.print(c);  
        buffer+=c;      
        if (c == '\n' && currentLineIsBlank) {
         if(passEntered[currClient])
         {
           drawUser(client);
          
         }
         else
         {
          drawPass(client);
         }
         break;
        }
        if (c == '\n') {
          
          currentLineIsBlank = true;
          buffer="";      
        } else if (c == '\r') {  
          
          if((loginCount[currClient] > 1) && (buffer.indexOf("Authorization: Basic ") >= 0))
          {            
            for(int i = buffer.indexOf("Authorization: Basic ")+21; i < buffer.length()-1; i++)
            {
              encoded[i-(buffer.indexOf("Authorization: Basic ")+21)] = buffer[i];
            }
            
            base64_decode(decoded , encoded , buffer.length() - 21 - 1);
            
            accounts = SD.open("accounts.txt");
            if (accounts)
            {
              Serial.print("reading accounts.txt...");
              int userStart = -1;
              int userEnd = -1;
              boolean failed = false;
             while(!passEntered[currClient] && !failed )
             {
              boolean found = false;
              unsigned long i = userStart + 1;
              while(!found)
              {
                if(!accounts.seek(i))
                {
                  found = true;
                  failed = true;
                }
                char buf[10];
                accounts.read(buf, 6);      
                if(strncmp(buf, userHeader, 6) == 0)
                {
                    userStart = i;
                    found = true;
                }
                i++;
              }
              found = false;
              i = userEnd + 1;
              while(!found)
              {
                if(!accounts.seek(i))
                {
                  found = true;
                  failed = true;
                }
                char buf[10];
                accounts.read(buf, 7);      
                if(strncmp(buf, userFooter, 7) == 0)
                {
                    userEnd = i;
                    found = true;
                }
                i++;
              }
              if(!failed)
              {
                accounts.seek(userStart + 6);
                passEntered[currClient] = true;
                i = 0;
                while(accounts.position() != userEnd-2)
                {
                  Serial.print(accounts.peek());
                  if(decoded[i] != accounts.read())
                  {
                    passEntered[currClient] = false;
                  }
                  i++;
                }
                if(passEntered[currClient])
                {
                  int tempPos = accounts.position();
                  accounts.seek(userEnd - 1);
                  permissions[currClient] = accounts.read();
                  accounts.seek(tempPos);
                }
              }




             }
              accounts.close();
            
            } else {
              // if the file didn't open, print an error:
              Serial.println("error opening test.txt");
            }

            
            
            
          }
          
          if( passEntered[currClient])
          {
            
            if(buffer.indexOf("GET /?status=1")>=0)
              digitalWrite(8,HIGH);  
            
            if(buffer.indexOf("GET /?status=0")>=0)
              digitalWrite(8,LOW);  
          }
        }
        else {
          
          currentLineIsBlank = false;
        }
      }
    }
    
    client.stop();
  }
}

void drawUser(EthernetClient client)
{
  client.println("HTTP/1.1 200 OK");
           client.println("Content-Type: text/html");
          client.println();
          

            client.print("<BODY BGCOLOR=#000000 TEXT=#FFFFFF LINK=#FFFFFF VLINK=#FFFFFF>");
            
            client.print("<font color='blue' size=7>Welcome  ");
            
            if(permissions[currClient] == 'u')
              client.print("user ");
              
            if(permissions[currClient] == 'a')
              client.print("admin ");
              
              
          
          
          client.print(currClient);
          
          client.print(" </font>");
          
          client.println("<br />");
          client.println("<br />");
          
          if (digitalRead(8)){  
            client.print(" LED is <font color='green'>ON</font>");
          }else{
            client.print(" LED is <font color='red'>OFF</font>");
          }
          client.println("<br />");
          
          client.print("<FORM action=\"http://");
          client.print(Ethernet.localIP()[0]);
          client.print(".");
          client.print(Ethernet.localIP()[1]);
          client.print(".");
          client.print(Ethernet.localIP()[2]);
          client.print(".");
          client.print(Ethernet.localIP()[3]);
          client.print("/\" >");
          
          client.print("<P> <INPUT type=\"radio\" name=\"status\" value=\"1\">ON");
          client.print("<P> <INPUT type=\"radio\" name=\"status\" value=\"0\">OFF");
          client.print("<P> <INPUT type=\"submit\" value=\"Submit\"> ");
          client.print("</FORM>");
          
}

void drawPass(EthernetClient client)
{
             client.println("HTTP/1.1 401 Access Denied");
          client.println("WWW-Authenticate: Basic realm=\"a\"");
          
          client.println("Content-Type: text/html");
          client.println();
          

            client.print("<BODY BGCOLOR=#000000 TEXT=#FFFFFF LINK=#FFFFFF VLINK=#FFFFFF>");
            client.print("ERROR: ACCESS DENIED");
}


Basically it is a password protected led on pin 8. all of the users are stored on a SD card in a file "accounts.txt" with the format of:
<user>username:password:p</user> where p is a for admin or u for user
« Last Edit: February 06, 2013, 04:16:56 pm by ematson5897 » Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    String buffer = ""; 

Unfortunately using the String class is a very bad idea. It fragments your available RAM in no time, especially if used the way you use it. Additionally there's a bug in the freeing of dynamically allocated memory in the current IDE versions which makes using the String class even worse. If you don't want to be forced to reset your Arduino every few requests you should eliminate the String class from your project.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 197
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok. I guess I need to whip up a function to replicate indexOf in a char array


EDIT:
Got it. Now for implementation
Code:
int findStr(char * strA, char * strB)
{
  int location = strstr(strA , strB)-strA+1;
  if(location<0)
  {
    return -1;
  }
  return location;
}
« Last Edit: February 07, 2013, 04:21:38 pm by ematson5897 » Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9541
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If you don't want to be forced to reset your Arduino every few requests you should eliminate the String class from your project.

I've got some simple server code that uses the String class and had the server respond to a client request 500,000+ times with out a crash. Perhaps your code is defective.
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I've got some simple server code that uses the String class and had the server respond to a client request 500,000+ times with out a crash. Perhaps your code is defective.

If you are very cautious and know where the class is defective for en embedded environment, this is possible. But generally it's probably the worst decision of the Arduino makers to have this class included in the IDE. The way the OP uses the class he won't be able to answer 500'000 requests. And he does nothing the documentation says you shouldn't do.
Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9541
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I've got some simple server code that uses the String class and had the server respond to a client request 500,000+ times with out a crash. Perhaps your code is defective.

If you are very cautious and know where the class is defective for en embedded environment, this is possible. But generally it's probably the worst decision of the Arduino makers to have this class included in the IDE. The way the OP uses the class he won't be able to answer 500'000 requests. And he does nothing the documentation says you shouldn't do.

Well, guess we will see if the deletion of the String class fixes the OP's issue. Specifically which String useage in the OP's origional posted code is causing his issue? Did the String memory location "go out of scope" in the OP's code? The issue you pointed to (below) may well fix any "bug" issue by emptying the memory location such that there is no longer memory that needs to be freeded in that location. I read closely the anti String posting and don't remember ever actually seeing an issue being fixed by the removal of String useage.  I'll observe to see how this plays out.

Code:
   String buffer = "";  
« Last Edit: February 08, 2013, 11:56:33 am by zoomkat » Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5144
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I read closely the anti String posting and don't remember ever actually seeing an issue being fixed by the removal of String useage.

I had several threads where the change from the String class to using character arrays fixed the problems.

Anyway, I didn't say that the line I posted was posing problems for the OP, that was just the indication that he uses the String class. Because I've seen lots of strange behaviors because of the usage of the String class, that's always the first thing I try to eliminate.
Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9541
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I read closely the anti String posting and don't remember ever actually seeing an issue being fixed by the removal of String useage.

I had several threads where the change from the String class to using character arrays fixed the problems.

Anyway, I didn't say that the line I posted was posing problems for the OP, that was just the indication that he uses the String class. Because I've seen lots of strange behaviors because of the usage of the String class, that's always the first thing I try to eliminate.

Also DO NOT FLY ON AIRPLANES BECAUSE ONE CRASHED ONCE!!! I'm not a programmer, but I do look at the code where the Strings warnings are given, and the code posted usually does not involve the processes that supposedly invoke the "bug" as described by the "bug gurus". Giving String warnings that do not have to do with the issue being discussed is just a red flag for me that the people giving the warnings don't really understand the "bug" that they warning about.
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Pages: [1] 2   Go Up
Jump to: