Arduino for esp8266中有两个DNS服务相关的库:html
看看DNSServer具体工做原理:
web
ESP8266使用DNS服务(通常和WebServer服务一块儿使用,WebServer请回顾 ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用),请在代码中加入如下头文件:浏览器
#include <DNSServer.h>
讲解方法以前,先来看看博主总结的百度脑图:
服务器
经常使用方法很是简单,就4个方法,毕竟DNS服务器的功能比较单一。网络
函数说明:dom
/** * 启动DNS服务器 * @param port 端口号 DNS端口通常占用53 * @param domainName 映射域名 * @param resolvedIP 映射IP地址 * @return bool 是否启动成功 */ bool start(const uint16_t &port, const String &domainName, const IPAddress &resolvedIP);
源码说明:函数
bool DNSServer::start(const uint16_t &port, const String &domainName, const IPAddress &resolvedIP) { _port = port; _buffer = NULL; _domainName = domainName; _resolvedIP[0] = resolvedIP[0]; _resolvedIP[1] = resolvedIP[1]; _resolvedIP[2] = resolvedIP[2]; _resolvedIP[3] = resolvedIP[3]; downcaseAndRemoveWwwPrefix(_domainName); //启动了UDP服务 监听客户端向DNS服务器查询域名 return _udp.begin(_port) == 1; }
函数说明:oop
/** * 中止DNS服务器 */ void stop();
源码说明:网站
void DNSServer::stop() { //中止udp服务 _udp.stop(); free(_buffer); _buffer = NULL; }
函数说明:ui
/** * 设置错误响应码 * @param DNSReplyCode 错误响应码 */ void setErrorReplyCode(const DNSReplyCode &replyCode);
DNSReplyCode 定义以下:
enum class DNSReplyCode { NoError = 0, FormError = 1, ServerFailure = 2, //服务错误 NonExistentDomain = 3, NotImplemented = 4,//未定义 Refused = 5,//拒绝访问 YXDomain = 6, YXRRSet = 7, NXRRSet = 8 };
函数说明:
/** * 处理DNS请求服务 */ void processNextRequest();
源码说明:
/** * 处理DNS请求服务 */ void DNSServer::processNextRequest() { //获取UDP请求内容 _currentPacketSize = _udp.parsePacket(); if (_currentPacketSize) { if (_buffer != NULL) free(_buffer); _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); if (_buffer == NULL) return; _udp.read(_buffer, _currentPacketSize); _dnsHeader = (DNSHeader*) _buffer; //判断请求是否查找域名映射的IP地址 *在这里有很是特殊做用 读者请注意 if (_dnsHeader->QR == DNS_QR_QUERY && _dnsHeader->OPCode == DNS_OPCODE_QUERY && requestIncludesOnlyOneQuestion() && (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) ) { //返回IP地址 replyWithIP(); } else if (_dnsHeader->QR == DNS_QR_QUERY) { //响应错误码 replyWithCustomCode(); } free(_buffer); _buffer = NULL; } } /** * 响应域名对应的IP地址 */ void DNSServer::replyWithIP() { if (_buffer == NULL) return; _dnsHeader->QR = DNS_QR_RESPONSE; _dnsHeader->ANCount = _dnsHeader->QDCount; _dnsHeader->QDCount = _dnsHeader->QDCount; //_dnsHeader->RA = 1; _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); _udp.write(_buffer, _currentPacketSize); _udp.write((uint8_t)192); // answer name is a pointer _udp.write((uint8_t)12); // pointer to offset at 0x00c _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) _udp.write((uint8_t)1); _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) _udp.write((uint8_t)1); _udp.write((unsigned char*)&_ttl, 4); // Length of RData is 4 bytes (because, in this case, RData is IPv4) _udp.write((uint8_t)0); _udp.write((uint8_t)4); _udp.write(_resolvedIP, sizeof(_resolvedIP)); _udp.endPacket(); #ifdef DEBUG_ESP_DNS DEBUG_ESP_PORT.printf("DNS responds: %s for %s\n", IPAddress(_resolvedIP).toString().c_str(), getDomainNameWithoutWwwPrefix().c_str() ); #endif } /** * 响应错误码 */ void DNSServer::replyWithCustomCode() { if (_buffer == NULL) return; _dnsHeader->QR = DNS_QR_RESPONSE; _dnsHeader->RCode = (unsigned char)_errorReplyCode; _dnsHeader->QDCount = 0; _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); _udp.write(_buffer, sizeof(DNSHeader)); _udp.endPacket(); }
注意点:
实验说明
在手机浏览器访问 "www.danpianji.com"会显示“Hello World”
实验源码
/** * 功能描述:在手机浏览器访问 "www.danpianji.com"会显示“Hello World” */ #include <ESP8266WiFi.h> #include <DNSServer.h> #include <ESP8266WebServer.h> //调试定义 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) #define DebugPrintF(...) Serial.printf( __VA_ARGS__ ) const byte DNS_PORT = 53; IPAddress apIP(192, 168, 1, 1); DNSServer dnsServer; ESP8266WebServer webServer(80); void setup() { DebugBegin(115200); WiFi.mode(WIFI_AP); WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); WiFi.softAP("DNSServer example"); // modify TTL associated with the domain name (in seconds) // default is 60 seconds dnsServer.setTTL(300); // set which return code will be used for all other domains (e.g. sending // ServerFailure instead of NonExistentDomain will reduce number of queries // sent by clients) // default is DNSReplyCode::NonExistentDomain dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure); // 启动DNS server,映射主机名为 www.danpianji.com bool status = dnsServer.start(DNS_PORT, "www.danpianji.com", apIP); if(status){ DebugPrintln("start dnsserver success."); }else{ DebugPrintln("start dnsserver failed."); } // simple HTTP server to see that DNS server is working webServer.onNotFound([]() { String message = "Hello World!\n\n"; message += "URI: "; message += webServer.uri(); webServer.send(200, "text/plain", message); }); webServer.begin(); } void loop() { dnsServer.processNextRequest(); webServer.handleClient(); }
实验结果
会看到一个DNSServer example开放式AP热点,链接上:
而后在手机浏览器访问 www.danpianji.com
实验说明
一般,当咱们连上一些wifi热点,只要没有认证手机号码信息,不管访问哪一个页面都会弹出一个web认证页面(这就是商家用来收集手机用户信息的一种手段,慎重),这就是 Portal 认证。
Portal服务器也就是接收Portal客户端认证请求的服务器端系统,其主要做用是提供免费的门户服务和基于Web认证的界面,以及接入设备交互认证客户端的认证信息。其中的Web认证方案首先须要给用户分配一个地址,用于访问门户网站。
Portal 基于浏览器,采用的是B/S构架, 对不一样权限的用户下发不一样的VLAN 访问不一样的服务器资源,当经过认证后才能访问internet资源,Portal认证方式不须要安装认证客户端, 减小了客户端的维护工做量,便于运营。
能够在Portal页面上开展业务拓展,如展现商家广告, 联系方式等基本信息。Portal普遍应用于运营商、学校等网络。
经过DNSServer,咱们也可使用到Portal认证
实验源码
/** * 功能描述:portal认证 */ #include <DNSServer.h> #include <ESP8266WebServer.h> #include <ESP8266WiFi.h> //调试定义 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) #define DebugPrintF(...) Serial.printf( __VA_ARGS__ ) const byte DNS_PORT = 53; IPAddress apIP(192, 168, 1, 1); DNSServer dnsServer; ESP8266WebServer webServer(80); String responseHTML = "" "<!DOCTYPE html><html><head><title>CaptivePortal</title></head><body>" "<h1>Hello World!</h1><p>This is a captive portal example. All requests will " "be redirected here.</p></body></html>"; void setup() { DebugBegin(115200); WiFi.mode(WIFI_AP); WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); WiFi.softAP("DNSServer CaptivePortal example"); // 全部请求都映射到一个具体地址 dnsServer.start(DNS_PORT, "*", apIP); // replay to all requests with same HTML webServer.onNotFound([]() { DebugPrintln("webServer handle."); webServer.send(200, "text/html", responseHTML); }); webServer.begin(); } void loop() { dnsServer.processNextRequest(); webServer.handleClient(); }
实验结果
会看到一个 DNSServer CaptivePortal example 开放式AP热点,链接上:
而后在手机浏览器访问 www.danpianji.com
DNSServer也是相对来讲很是重要的一章,特别对于web配网,须要使用到它,请读者认真理解使用。