Created
January 22, 2011 03:44
-
-
Save laclefyoshi/790835 to your computer and use it in GitHub Desktop.
DNS server like dnsmasq with Arduino and EthernetShield
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -*- mode: c++ -*- | |
/** | |
Copyright: (c) SAEKI Yoshiyasu | |
License : MIT-style license | |
<http://www.opensource.org/licenses/mit-license.php> | |
last updated: 2011/01/21 | |
**/ | |
#include <SPI.h> | |
#include <Ethernet.h> | |
#include <Udp.h> | |
#include <SD.h> | |
// setting for EthernetShield | |
byte mac[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; | |
byte ip[] = {192, 168, 254, 100}; | |
const int sdSelect = 4; | |
char hostsPath[] = "/etc/hosts"; | |
unsigned int listenPort = 53; | |
byte remoteIp[4]; | |
unsigned int remotePort; | |
#define PACKET_MAX_SIZE 128 | |
char requestBuffer[PACKET_MAX_SIZE]; | |
char responseBuffer[PACKET_MAX_SIZE]; | |
char reqDomain[40]; | |
byte resIp[4]; | |
struct ADPair { | |
char domain[40]; | |
byte ipaddr[4]; | |
}; | |
#define MAX_PAIR_SIZE 7 | |
struct ADPair pairs[MAX_PAIR_SIZE]; | |
int pairIdx = 0; | |
void setup() { | |
Ethernet.begin(mac, ip); | |
Udp.begin(listenPort); | |
// Serial.begin(9600); | |
// Serial.print("Init SD card..."); | |
if (!SD.begin(sdSelect)) { | |
// Serial.println("SD Card failed"); | |
return; | |
} | |
// Serial.println("done."); | |
readHosts(); | |
} | |
void loop() { | |
int requestSize = Udp.available(); | |
if(requestSize) { | |
Udp.readPacket(requestBuffer, PACKET_MAX_SIZE, remoteIp, remotePort); | |
int type = (requestBuffer[2] >> 3) & 15; | |
if(type == 0) { // nomal request | |
getReqDomain(); | |
if(reqDomain[0] != '\0') { // request exists | |
setResIp(); | |
int responseSize = generateResponseData(requestSize); | |
Udp.sendPacket((uint8_t *)responseBuffer, (uint16_t)(responseSize - 1), | |
remoteIp, remotePort); | |
} | |
} | |
} | |
} | |
void readHosts() { | |
File hostsFile = SD.open(hostsPath); | |
if (hostsFile) { | |
char line[90]; | |
char domain[40]; | |
char alias[30]; | |
byte ipaddr[4]; | |
while (hostsFile.available()) { | |
int idx = 0; | |
char c; | |
do { | |
c = hostsFile.read(); | |
if(c == '#') { | |
while(c != '\n') { | |
c = hostsFile.read(); | |
} | |
break; | |
} | |
line[idx++] = c; | |
} while(c != '\n'); | |
line[idx] = '\0'; | |
if(sscanf(line, "%d.%d.%d.%d %s %s", | |
&ipaddr[0], &ipaddr[1], &ipaddr[2], &ipaddr[3], domain, alias) == 6) { | |
strcpy(pairs[pairIdx].domain, domain); | |
for(int j = 0; j < 4; j++) { | |
pairs[pairIdx].ipaddr[j] = ipaddr[j]; | |
} | |
pairIdx++; | |
strcpy(pairs[pairIdx].domain, alias); | |
for(int j = 0; j < 4; j++) { | |
pairs[pairIdx].ipaddr[j] = ipaddr[j]; | |
} | |
pairIdx++; | |
} else if(sscanf(line, "%d.%d.%d.%d %s", | |
&ipaddr[0], &ipaddr[1], &ipaddr[2], &ipaddr[3], domain) == 5) { | |
strcpy(pairs[pairIdx].domain, domain); | |
for(int j = 0; j < 4; j++) { | |
pairs[pairIdx].ipaddr[j] = ipaddr[j]; | |
} | |
pairIdx++; | |
} | |
if(pairIdx >= MAX_PAIR_SIZE) { | |
break; | |
} | |
} | |
free(line); | |
free(domain); | |
free(alias); | |
free(ipaddr); | |
} else { | |
// Serial.println("error: open /etc/hosts"); | |
} | |
hostsFile.close(); | |
// Serial.print("entries: "); Serial.println(pairIdx); | |
} | |
void getReqDomain() { | |
int ini = 12; | |
int lon = requestBuffer[ini]; | |
int i = 0; | |
while(lon != 0) { | |
for(int j = 0; j < lon; j++) { | |
reqDomain[i++] = requestBuffer[ini + j + 1]; | |
} | |
reqDomain[i++] = '.'; | |
ini += lon + 1; | |
lon = requestBuffer[ini]; | |
} | |
reqDomain[i] = '\0'; | |
// Serial.println(reqDomain); | |
} | |
void setResIp() { | |
for(int t = 0; t < 4; t++) { | |
resIp[t] = 0; | |
} | |
reqDomain[strlen(reqDomain) - 1] = '\0'; | |
for(int pI = 0; pI < pairIdx; pI++) { | |
if(strcmp(pairs[pI].domain, reqDomain) == 0) { | |
for(int t = 0; t < 4; t++) { | |
resIp[t] = pairs[pI].ipaddr[t]; | |
} | |
} | |
} | |
} | |
int generateResponseData(int requestSize){ | |
// RFC 1035 | |
int resIndex = 0; | |
for(int k = 0; k < 2; k++) { // identification | |
responseBuffer[resIndex++] = requestBuffer[k]; | |
} | |
if(resIp[0] == 0) { // no name | |
responseBuffer[resIndex++] = '\x81'; // normal server | |
responseBuffer[resIndex++] = '\x02'; // server failure | |
for(int k = 4; k < 6; k++) { // question | |
responseBuffer[resIndex++] = requestBuffer[k]; | |
} | |
for(int k = 4; k < 6; k++) { // answer | |
responseBuffer[resIndex++] = '\x00'; | |
} | |
for(int k = 0; k < 4; k++) { // authority, addition | |
responseBuffer[resIndex++] = '\x00'; | |
} | |
} else { // name exists | |
responseBuffer[resIndex++] = '\x85'; // normal server | |
// authoritative | |
responseBuffer[resIndex++] = '\x80'; // recursive | |
// no error | |
for(int k = 4; k < 6; k++) { // question | |
responseBuffer[resIndex++] = requestBuffer[k]; | |
} | |
for(int k = 4; k < 6; k++) { // answer | |
responseBuffer[resIndex++] = requestBuffer[k]; | |
} | |
for(int k = 0; k < 4; k++) { // authority, addition | |
responseBuffer[resIndex++] = '\x00'; | |
} | |
for(int k = 12; k < requestSize - 8; k++) { // question | |
responseBuffer[resIndex++] = requestBuffer[k]; | |
} | |
responseBuffer[resIndex++] = '\xc0'; | |
responseBuffer[resIndex++] = '\x0c'; | |
responseBuffer[resIndex++] = '\x00'; // type | |
responseBuffer[resIndex++] = '\x01'; | |
responseBuffer[resIndex++] = '\x00'; // class | |
responseBuffer[resIndex++] = '\x01'; | |
responseBuffer[resIndex++] = '\x00'; // ttl | |
responseBuffer[resIndex++] = '\x00'; | |
responseBuffer[resIndex++] = '\x00'; | |
responseBuffer[resIndex++] = '\x3c'; | |
responseBuffer[resIndex++] = '\x00'; // ip length | |
responseBuffer[resIndex++] = '\x04'; | |
responseBuffer[resIndex++] = resIp[0]; // ip | |
responseBuffer[resIndex++] = resIp[1]; | |
responseBuffer[resIndex++] = resIp[2]; | |
responseBuffer[resIndex++] = resIp[3]; | |
} | |
responseBuffer[resIndex++] = '\x00'; // end | |
return resIndex; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment