Bonjour/Zerconf library

Dependencies:   mbed

Committer:
dirkx
Date:
Sat Jul 31 14:30:45 2010 +0000
Revision:
4:d9f5c4abc5f8
Parent:
3:e1d86543ec50
Child:
5:8e53abda9900

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dirkx 4:d9f5c4abc5f8 1 /* Class: mDNSResponder
dirkx 4:d9f5c4abc5f8 2 * Copyright 1991, 2003, 2010 Dirk-Willem van Gulik <dirkx(at)apache(punto)org>
dirkx 4:d9f5c4abc5f8 3 *
dirkx 4:d9f5c4abc5f8 4 * License: Any BSD or ASF License.
dirkx 4:d9f5c4abc5f8 5 *
dirkx 4:d9f5c4abc5f8 6 * Rough and ready port of some mDNS code.
dirkx 4:d9f5c4abc5f8 7 *
dirkx 4:d9f5c4abc5f8 8 * Typical use is something like
dirkx 4:d9f5c4abc5f8 9 *
dirkx 4:d9f5c4abc5f8 10 * EthernetNetIf eth;
dirkx 4:d9f5c4abc5f8 11 * HTTPServer svr;
dirkx 4:d9f5c4abc5f8 12 * mDNSResponder mdns;
dirkx 4:d9f5c4abc5f8 13 *
dirkx 4:d9f5c4abc5f8 14 * int main()...
dirkx 4:d9f5c4abc5f8 15 *
dirkx 4:d9f5c4abc5f8 16 * // get internet
dirkx 4:d9f5c4abc5f8 17 * EthernetErr ethErr = eth.setup();
dirkx 4:d9f5c4abc5f8 18 * ... etc ..
dirkx 4:d9f5c4abc5f8 19 *
dirkx 4:d9f5c4abc5f8 20 * // set up some server
dirkx 4:d9f5c4abc5f8 21 * svr.addHandler<SimpleHandler>("/"); //Default handler
dirkx 4:d9f5c4abc5f8 22 * svr.bind(80); * *
dirkx 4:d9f5c4abc5f8 23
dirkx 4:d9f5c4abc5f8 24 * // Extract the IP address.
dirkx 4:d9f5c4abc5f8 25 * IpAddr ip = eth.getIp();
dirkx 4:d9f5c4abc5f8 26 * printf("mbed IP Address is %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
dirkx 4:d9f5c4abc5f8 27 *
dirkx 4:d9f5c4abc5f8 28 * // Announce ourselves.
dirkx 4:d9f5c4abc5f8 29 * mdns.announce(ip, "fred", "_http._tcp", 80, "The Little Server that Could", "path=/demo");
dirkx 4:d9f5c4abc5f8 30 *
dirkx 4:d9f5c4abc5f8 31 * while()... enter some run loop
dirkx 4:d9f5c4abc5f8 32 * ...
dirkx 4:d9f5c4abc5f8 33 *
dirkx 4:d9f5c4abc5f8 34 * This will cause http://fred.local./demo to be announced as 'The Little Server that Could'.
dirkx 4:d9f5c4abc5f8 35 *
dirkx 4:d9f5c4abc5f8 36 * Or as another example: (http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt)
dirkx 4:d9f5c4abc5f8 37 * and the various RFCs:
dirkx 4:d9f5c4abc5f8 38 *
dirkx 4:d9f5c4abc5f8 39 * mdns.announce(ip, "_ssh._tcp", 22, SSH to Serial Gateway", NULL);
dirkx 4:d9f5c4abc5f8 40 *
dirkx 4:d9f5c4abc5f8 41 * CAVEAT - a lot of the buffer overrun and copy checks
dirkx 4:d9f5c4abc5f8 42 * where removed; and this is not anywhere near
dirkx 4:d9f5c4abc5f8 43 * threadsafve or sane. Not for production use.
dirkx 4:d9f5c4abc5f8 44 */
dirkx 4:d9f5c4abc5f8 45 #include "lwip/opt.h"
dirkx 4:d9f5c4abc5f8 46 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
dirkx 4:d9f5c4abc5f8 47
dirkx 4:d9f5c4abc5f8 48 #define __DEBUG
dirkx 4:d9f5c4abc5f8 49 #include "dbg/dbg.h"
dirkx 4:d9f5c4abc5f8 50
dirkx 4:d9f5c4abc5f8 51 #include "mDNSResponder.h"
dirkx 4:d9f5c4abc5f8 52 #include <stdio.h>
dirkx 4:d9f5c4abc5f8 53
dirkx 4:d9f5c4abc5f8 54 #ifndef DNS_RRTYPE_SRV
dirkx 4:d9f5c4abc5f8 55 #define DNS_RRTYPE_SRV (33)
dirkx 4:d9f5c4abc5f8 56 #endif
dirkx 4:d9f5c4abc5f8 57
dirkx 4:d9f5c4abc5f8 58 #ifndef DNS_LOCAL
dirkx 4:d9f5c4abc5f8 59 #define DNS_LOCAL "local"
dirkx 4:d9f5c4abc5f8 60 #endif
dirkx 4:d9f5c4abc5f8 61
dirkx 4:d9f5c4abc5f8 62 mDNSResponder::mDNSResponder() : NetService(false),
dirkx 4:d9f5c4abc5f8 63 moi_txt(NULL), moi_port(0), moi_ip(0),
dirkx 4:d9f5c4abc5f8 64 moi_name(NULL), moi_proto(NULL),
dirkx 4:d9f5c4abc5f8 65 moi_local_proto(NULL), moi_local_name(NULL), moi_local_pglue(NULL),
dirkx 4:d9f5c4abc5f8 66 #ifdef MDNS_QCACHE
dirkx 4:d9f5c4abc5f8 67 labelCacheCnt(0), labelCacheOffset(0),
dirkx 4:d9f5c4abc5f8 68 #endif
dirkx 4:d9f5c4abc5f8 69 announcer()
dirkx 4:d9f5c4abc5f8 70 {
dirkx 4:d9f5c4abc5f8 71 initLabelCache(0);
dirkx 4:d9f5c4abc5f8 72 }
dirkx 4:d9f5c4abc5f8 73
dirkx 4:d9f5c4abc5f8 74 mDNSResponder::~mDNSResponder() {
dirkx 4:d9f5c4abc5f8 75 announcer.stop();
dirkx 4:d9f5c4abc5f8 76 close();
dirkx 4:d9f5c4abc5f8 77 }
dirkx 4:d9f5c4abc5f8 78
dirkx 4:d9f5c4abc5f8 79 void mDNSResponder::announce(IpAddr ip, const char * ldn, const char * proto, uint16_t port, const char * name, char ** txt) {
dirkx 4:d9f5c4abc5f8 80 Host localhost(IpAddr(MCAST), MDNS_PORT, NULL /* fqdn */);
dirkx 4:d9f5c4abc5f8 81
dirkx 4:d9f5c4abc5f8 82 m_pUDPSocket = new UDPSocket;
dirkx 4:d9f5c4abc5f8 83 m_pUDPSocket->bind(localhost);
dirkx 4:d9f5c4abc5f8 84
dirkx 4:d9f5c4abc5f8 85 m_pUDPSocket->setOnEvent(this, &mDNSResponder::onUDPSocketEvent);
dirkx 4:d9f5c4abc5f8 86
dirkx 4:d9f5c4abc5f8 87 moi_port = port;
dirkx 4:d9f5c4abc5f8 88 moi_txt = txt;
dirkx 4:d9f5c4abc5f8 89 moi_ip = ip;
dirkx 4:d9f5c4abc5f8 90 moi_proto = proto;
dirkx 4:d9f5c4abc5f8 91 moi_name = name;
dirkx 4:d9f5c4abc5f8 92
dirkx 4:d9f5c4abc5f8 93 moi_local_proto = (char *)malloc(128);
dirkx 4:d9f5c4abc5f8 94 moi_local_name = (char *)malloc(128);
dirkx 4:d9f5c4abc5f8 95 moi_local_pglue = (char *)malloc(128);
dirkx 4:d9f5c4abc5f8 96
dirkx 4:d9f5c4abc5f8 97 snprintf(moi_local_proto,128,"%s.%s.", moi_proto, DNS_LOCAL);
dirkx 4:d9f5c4abc5f8 98 snprintf(moi_local_name,128,"%s.%s.", ldn, DNS_LOCAL);
dirkx 4:d9f5c4abc5f8 99 snprintf(moi_local_pglue,128,"%s.%s.%s.", moi_name,moi_proto, DNS_LOCAL);
dirkx 4:d9f5c4abc5f8 100
dirkx 4:d9f5c4abc5f8 101 // Gratuis intro - and repeat such regularly.. taking some
dirkx 4:d9f5c4abc5f8 102 // care to not go beyond DHCP limits - but not more often
dirkx 4:d9f5c4abc5f8 103 // than makes sense for our TTL. See the .h file for the
dirkx 4:d9f5c4abc5f8 104 // various tradeoffs.
dirkx 4:d9f5c4abc5f8 105 //
dirkx 4:d9f5c4abc5f8 106 mDNSResponder::sendReply(DNS_RRTYPE_PTR, 0, localhost);
dirkx 4:d9f5c4abc5f8 107 announcer.start();
dirkx 4:d9f5c4abc5f8 108 }
dirkx 4:d9f5c4abc5f8 109
dirkx 4:d9f5c4abc5f8 110 void mDNSResponder::close() {
dirkx 4:d9f5c4abc5f8 111 m_pUDPSocket->resetOnEvent();
dirkx 4:d9f5c4abc5f8 112 m_pUDPSocket->close();
dirkx 4:d9f5c4abc5f8 113 delete m_pUDPSocket;
dirkx 4:d9f5c4abc5f8 114 }
dirkx 4:d9f5c4abc5f8 115
dirkx 4:d9f5c4abc5f8 116 void mDNSResponder::poll() { //Called by NetServices
dirkx 4:d9f5c4abc5f8 117 if (announcer.read_ms() > 1000 * MDNS_INTERVAL) {
dirkx 4:d9f5c4abc5f8 118
dirkx 4:d9f5c4abc5f8 119 Host mch(IpAddr(MCAST), MDNS_PORT, NULL);
dirkx 4:d9f5c4abc5f8 120 mDNSResponder::sendReply(DNS_RRTYPE_PTR, 0, mch);
dirkx 4:d9f5c4abc5f8 121
dirkx 4:d9f5c4abc5f8 122 announcer.reset();
dirkx 4:d9f5c4abc5f8 123 }
dirkx 4:d9f5c4abc5f8 124 }
dirkx 4:d9f5c4abc5f8 125
dirkx 4:d9f5c4abc5f8 126 char * index(char * str, char c) {
dirkx 4:d9f5c4abc5f8 127 for (;str && *str;str++) {
dirkx 4:d9f5c4abc5f8 128 if (*str == c) return str;
dirkx 4:d9f5c4abc5f8 129 };
dirkx 4:d9f5c4abc5f8 130 return NULL;
dirkx 4:d9f5c4abc5f8 131 }
dirkx 4:d9f5c4abc5f8 132
dirkx 4:d9f5c4abc5f8 133 #ifdef MDNS_QCACHE
dirkx 4:d9f5c4abc5f8 134 void mDNSResponder::initLabelCache(char * off) {
dirkx 4:d9f5c4abc5f8 135 labelCacheOffset = off;
dirkx 4:d9f5c4abc5f8 136 labelCacheCnt = 0;
dirkx 4:d9f5c4abc5f8 137 memset(_cache_off,0, sizeof(_cache_off)); // Rely on min value to be 12
dirkx 4:d9f5c4abc5f8 138 };
dirkx 4:d9f5c4abc5f8 139
dirkx 4:d9f5c4abc5f8 140 uint16_t mDNSResponder::checkLabelCache(char * name) {
dirkx 4:d9f5c4abc5f8 141 // Bail out if not initialized with a valid (>12) offset.
dirkx 4:d9f5c4abc5f8 142 //
dirkx 4:d9f5c4abc5f8 143 if (!labelCacheOffset)
dirkx 4:d9f5c4abc5f8 144 return 0;
dirkx 4:d9f5c4abc5f8 145
dirkx 4:d9f5c4abc5f8 146 for (int i=0; i < MDNS_MAXCACHEDNSLABELS; i++)
dirkx 4:d9f5c4abc5f8 147 if (_cache_off[i] && !strcmp(_cache_och[i],name))
dirkx 4:d9f5c4abc5f8 148 return _cache_off[i];
dirkx 4:d9f5c4abc5f8 149 return 0;
dirkx 4:d9f5c4abc5f8 150 };
dirkx 4:d9f5c4abc5f8 151
dirkx 4:d9f5c4abc5f8 152 void mDNSResponder::addLabelCache(char * p, char * name) {
dirkx 4:d9f5c4abc5f8 153 // Bail out if not initialized with a valid (>12) offset.
dirkx 4:d9f5c4abc5f8 154 //
dirkx 4:d9f5c4abc5f8 155 if (!labelCacheOffset)
dirkx 4:d9f5c4abc5f8 156 return;
dirkx 4:d9f5c4abc5f8 157
dirkx 4:d9f5c4abc5f8 158 _cache_off[labelCacheCnt] = p - labelCacheOffset;
dirkx 4:d9f5c4abc5f8 159 _cache_och[labelCacheCnt] = name;
dirkx 4:d9f5c4abc5f8 160
dirkx 4:d9f5c4abc5f8 161 labelCacheCnt++;
dirkx 4:d9f5c4abc5f8 162 // we intentionally do not wack the first entries - as they are the most
dirkx 4:d9f5c4abc5f8 163 // likely ones to be used.
dirkx 4:d9f5c4abc5f8 164 if (labelCacheCnt>= MDNS_MAXCACHEDNSLABELS)
dirkx 4:d9f5c4abc5f8 165 labelCacheCnt = MDNS_MAXCACHEDNSLABELS / 3;
dirkx 4:d9f5c4abc5f8 166 };
dirkx 4:d9f5c4abc5f8 167 #else
dirkx 4:d9f5c4abc5f8 168 #define initLabelCache(x) {} /* Ignored */
dirkx 4:d9f5c4abc5f8 169 #define checkLabelCache(x) (0) /* never a hit */
dirkx 4:d9f5c4abc5f8 170 #define addLabelCache(x,y) {} /* Ignored */
dirkx 4:d9f5c4abc5f8 171 #endif
dirkx 4:d9f5c4abc5f8 172
dirkx 4:d9f5c4abc5f8 173 char * mDNSResponder::breakname(char *p, char *name) {
dirkx 4:d9f5c4abc5f8 174 int l = 0, de = 1;
dirkx 4:d9f5c4abc5f8 175 char * q;
dirkx 4:d9f5c4abc5f8 176 uint16_t off;
dirkx 4:d9f5c4abc5f8 177
dirkx 4:d9f5c4abc5f8 178 do {
dirkx 4:d9f5c4abc5f8 179 if ((off = checkLabelCache(name)) != 0) {
dirkx 4:d9f5c4abc5f8 180 *p++ = 192 + (off >> 8);
dirkx 4:d9f5c4abc5f8 181 *p++ = (off & 0xFF);
dirkx 4:d9f5c4abc5f8 182 return p;
dirkx 4:d9f5c4abc5f8 183 } else {
dirkx 4:d9f5c4abc5f8 184 addLabelCache(p, name);
dirkx 4:d9f5c4abc5f8 185 };
dirkx 4:d9f5c4abc5f8 186
dirkx 4:d9f5c4abc5f8 187 q = index(name,'.');
dirkx 4:d9f5c4abc5f8 188 if (!q) {
dirkx 4:d9f5c4abc5f8 189 q = name + strlen(name);
dirkx 4:d9f5c4abc5f8 190 de = 0;
dirkx 4:d9f5c4abc5f8 191 };
dirkx 4:d9f5c4abc5f8 192 l = q - name;
dirkx 4:d9f5c4abc5f8 193 *p++ = l;
dirkx 4:d9f5c4abc5f8 194 memcpy(p, name, l);
dirkx 4:d9f5c4abc5f8 195 p+=l;
dirkx 4:d9f5c4abc5f8 196 name = q + 1;
dirkx 4:d9f5c4abc5f8 197 } while (l && *name && de);
dirkx 4:d9f5c4abc5f8 198
dirkx 4:d9f5c4abc5f8 199 // terminating root field if any (not the case for
dirkx 4:d9f5c4abc5f8 200 // things like TXTs).
dirkx 4:d9f5c4abc5f8 201 if (de) *p++ = 0;
dirkx 4:d9f5c4abc5f8 202 return p;
dirkx 4:d9f5c4abc5f8 203 }
dirkx 4:d9f5c4abc5f8 204
dirkx 4:d9f5c4abc5f8 205 char * mDNSResponder::mRR(char *p, char * name, uint16_t tpe, uint16_t cls, uint32_t ttl) {
dirkx 4:d9f5c4abc5f8 206 uint16_t i = 0;
dirkx 4:d9f5c4abc5f8 207 uint32_t j = 0;
dirkx 4:d9f5c4abc5f8 208
dirkx 4:d9f5c4abc5f8 209 p = breakname(p, name);
dirkx 4:d9f5c4abc5f8 210
dirkx 4:d9f5c4abc5f8 211 // NOTE: Cannot assume proper byte boundaries; so
dirkx 4:d9f5c4abc5f8 212 // we assume the compiler does not allow that for
dirkx 4:d9f5c4abc5f8 213 // casts - and write it out with memcpy's
dirkx 4:d9f5c4abc5f8 214 //
dirkx 4:d9f5c4abc5f8 215 i = htons(tpe); // Type
dirkx 4:d9f5c4abc5f8 216 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 217 p+=2;
dirkx 4:d9f5c4abc5f8 218
dirkx 4:d9f5c4abc5f8 219 i = htons(cls); // Class
dirkx 4:d9f5c4abc5f8 220 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 221 p+=2;
dirkx 4:d9f5c4abc5f8 222
dirkx 4:d9f5c4abc5f8 223 j = htonl(ttl); // TTL (4 bytes)
dirkx 4:d9f5c4abc5f8 224 memcpy(p, &j, 4);
dirkx 4:d9f5c4abc5f8 225 p+=4;
dirkx 4:d9f5c4abc5f8 226
dirkx 4:d9f5c4abc5f8 227 return p;
dirkx 4:d9f5c4abc5f8 228 }
dirkx 4:d9f5c4abc5f8 229
dirkx 4:d9f5c4abc5f8 230 char * mDNSResponder::mRRLABEL(char *p, char * name, uint16_t tpe, char ** rr) {
dirkx 4:d9f5c4abc5f8 231 uint16_t i = 0;
dirkx 4:d9f5c4abc5f8 232
dirkx 4:d9f5c4abc5f8 233 p = mRR(p, name, tpe, DNS_RRCLASS_IN, MDNS_TTL); // Type, IN, TTL
dirkx 4:d9f5c4abc5f8 234
dirkx 4:d9f5c4abc5f8 235 // RR String
dirkx 4:d9f5c4abc5f8 236 char * q = p + 2;
dirkx 4:d9f5c4abc5f8 237
dirkx 4:d9f5c4abc5f8 238 for (;*rr;rr++)
dirkx 4:d9f5c4abc5f8 239 q = breakname(q, *rr);
dirkx 4:d9f5c4abc5f8 240
dirkx 4:d9f5c4abc5f8 241 i = htons(q - p - 2); // RDLEN
dirkx 4:d9f5c4abc5f8 242 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 243 return q;
dirkx 4:d9f5c4abc5f8 244 }
dirkx 4:d9f5c4abc5f8 245
dirkx 4:d9f5c4abc5f8 246 char * mDNSResponder::mPTR(char *p, char * name, char * r) {
dirkx 4:d9f5c4abc5f8 247 char *rr[] = { r, NULL };
dirkx 4:d9f5c4abc5f8 248 return mRRLABEL(p, name, DNS_RRTYPE_PTR, rr );
dirkx 4:d9f5c4abc5f8 249 }
dirkx 4:d9f5c4abc5f8 250
dirkx 4:d9f5c4abc5f8 251 char * mDNSResponder::mTXT(char *p, char * name, char ** rr) {
dirkx 4:d9f5c4abc5f8 252 return mRRLABEL(p, name, DNS_RRTYPE_TXT, rr);
dirkx 4:d9f5c4abc5f8 253 }
dirkx 4:d9f5c4abc5f8 254
dirkx 4:d9f5c4abc5f8 255 char * mDNSResponder::mARR(char *p, char * name, IpAddr ip) {
dirkx 4:d9f5c4abc5f8 256 uint16_t i = 0;
dirkx 4:d9f5c4abc5f8 257
dirkx 4:d9f5c4abc5f8 258 p = mRR(p, name, DNS_RRTYPE_A, DNS_RRCLASS_IN, MDNS_TTL ); // A, IN
dirkx 4:d9f5c4abc5f8 259
dirkx 4:d9f5c4abc5f8 260 i = htons(4); // RDLEN - we're just doing a single IPv4 address - our primary link ?
dirkx 4:d9f5c4abc5f8 261 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 262
dirkx 4:d9f5c4abc5f8 263 // IP already in network order.
dirkx 4:d9f5c4abc5f8 264 memcpy(p+2, &ip, 4);
dirkx 4:d9f5c4abc5f8 265
dirkx 4:d9f5c4abc5f8 266 return p + 2 + 4;
dirkx 4:d9f5c4abc5f8 267 }
dirkx 4:d9f5c4abc5f8 268
dirkx 4:d9f5c4abc5f8 269 char * mDNSResponder::mSRV(char *p, char * name, uint16_t port, char * rr) {
dirkx 4:d9f5c4abc5f8 270 uint16_t i = 0;
dirkx 4:d9f5c4abc5f8 271 char * q;
dirkx 4:d9f5c4abc5f8 272
dirkx 4:d9f5c4abc5f8 273 p = mRR(p, name, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, MDNS_TTL); // SRV, IN
dirkx 4:d9f5c4abc5f8 274
dirkx 4:d9f5c4abc5f8 275 // Keep space for RDLEN
dirkx 4:d9f5c4abc5f8 276 q = p;
dirkx 4:d9f5c4abc5f8 277 p+=2;
dirkx 4:d9f5c4abc5f8 278
dirkx 4:d9f5c4abc5f8 279 i = htons(1); // Priority
dirkx 4:d9f5c4abc5f8 280 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 281 p+=2;
dirkx 4:d9f5c4abc5f8 282
dirkx 4:d9f5c4abc5f8 283 i = htons(0); // Weight (see rfc2782)
dirkx 4:d9f5c4abc5f8 284 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 285 p+=2;
dirkx 4:d9f5c4abc5f8 286
dirkx 4:d9f5c4abc5f8 287 i = htons(port); // Port
dirkx 4:d9f5c4abc5f8 288 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 289 p+=2;
dirkx 4:d9f5c4abc5f8 290
dirkx 4:d9f5c4abc5f8 291 p = breakname(p, rr);
dirkx 4:d9f5c4abc5f8 292
dirkx 4:d9f5c4abc5f8 293 i = htons(p - q - 2); // RDLEN
dirkx 4:d9f5c4abc5f8 294 memcpy(q, &i, 2);
dirkx 4:d9f5c4abc5f8 295
dirkx 4:d9f5c4abc5f8 296 return p;
dirkx 4:d9f5c4abc5f8 297 }
dirkx 4:d9f5c4abc5f8 298
dirkx 4:d9f5c4abc5f8 299 char * mDNSResponder::qANY(char *p, char * name, uint16_t tpe, uint16_t cls) {
dirkx 4:d9f5c4abc5f8 300 uint16_t i = 0;
dirkx 4:d9f5c4abc5f8 301 p = breakname(p, name); // QNAME
dirkx 4:d9f5c4abc5f8 302
dirkx 4:d9f5c4abc5f8 303 i = htons(tpe); // QTYPE
dirkx 4:d9f5c4abc5f8 304 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 305 p+=2;
dirkx 4:d9f5c4abc5f8 306
dirkx 4:d9f5c4abc5f8 307 i = htons(cls); // QCLASS
dirkx 4:d9f5c4abc5f8 308 memcpy(p, &i, 2);
dirkx 4:d9f5c4abc5f8 309 p+=2;
dirkx 4:d9f5c4abc5f8 310
dirkx 4:d9f5c4abc5f8 311 return p;
dirkx 4:d9f5c4abc5f8 312 }
dirkx 4:d9f5c4abc5f8 313
dirkx 4:d9f5c4abc5f8 314 char * mDNSResponder::qPTR(char *p, char *name) {
dirkx 4:d9f5c4abc5f8 315 return qANY(p,name,DNS_RRTYPE_PTR,DNS_RRCLASS_IN);
dirkx 4:d9f5c4abc5f8 316 }
dirkx 4:d9f5c4abc5f8 317
dirkx 4:d9f5c4abc5f8 318 char * mDNSResponder::qA(char *p, char *name) {
dirkx 4:d9f5c4abc5f8 319 return qANY(p,name,DNS_RRTYPE_A,DNS_RRCLASS_IN);
dirkx 4:d9f5c4abc5f8 320 }
dirkx 4:d9f5c4abc5f8 321
dirkx 4:d9f5c4abc5f8 322 char * mDNSResponder::qSRV(char *p, char *name) {
dirkx 4:d9f5c4abc5f8 323 return qANY(p,name,DNS_RRTYPE_SRV,DNS_RRCLASS_IN);
dirkx 4:d9f5c4abc5f8 324 }
dirkx 4:d9f5c4abc5f8 325
dirkx 4:d9f5c4abc5f8 326 void mDNSResponder::mDNSResponder::sendReply(uint16_t t, uint16_t tid, Host dst) {
dirkx 4:d9f5c4abc5f8 327 // sent a reply - basically a precooked A/PTR/SRV with the TransactionID
dirkx 4:d9f5c4abc5f8 328 // and my URI squeezed in.
dirkx 4:d9f5c4abc5f8 329 char out[ 1500 ], *p;
dirkx 4:d9f5c4abc5f8 330 DNSPacket * op = (DNSPacket *) out;
dirkx 4:d9f5c4abc5f8 331
dirkx 4:d9f5c4abc5f8 332 initLabelCache(out); // Offsets are relative to the ID header.
dirkx 4:d9f5c4abc5f8 333
dirkx 4:d9f5c4abc5f8 334 op->tid = ntohs(tid);
dirkx 4:d9f5c4abc5f8 335 op->flags = ntohs(0x8000U); // Answer
dirkx 4:d9f5c4abc5f8 336 op->question_count = ntohs(1); // Courtesy copy of the question.
dirkx 4:d9f5c4abc5f8 337 op->answer_count = ntohs(1); // The record asked for
dirkx 4:d9f5c4abc5f8 338 op->a_count = ntohs(0);
dirkx 4:d9f5c4abc5f8 339 p = out + 12;
dirkx 4:d9f5c4abc5f8 340
dirkx 4:d9f5c4abc5f8 341 switch (t) {
dirkx 4:d9f5c4abc5f8 342 case DNS_RRTYPE_PTR: // PTR record, SRV, optional TXT and A with my own address.
dirkx 4:d9f5c4abc5f8 343 op->aa_count = ntohs(moi_txt ? 3 : 2);
dirkx 4:d9f5c4abc5f8 344 p = qPTR(p,moi_local_proto);
dirkx 4:d9f5c4abc5f8 345
dirkx 4:d9f5c4abc5f8 346 p = mPTR(p,moi_local_proto, moi_local_pglue);
dirkx 4:d9f5c4abc5f8 347 if (moi_txt && * moi_txt)
dirkx 4:d9f5c4abc5f8 348 p = mTXT(p,moi_local_pglue,moi_txt);
dirkx 4:d9f5c4abc5f8 349
dirkx 4:d9f5c4abc5f8 350 break;
dirkx 4:d9f5c4abc5f8 351 case DNS_RRTYPE_A: // A record (and nothing else)
dirkx 4:d9f5c4abc5f8 352 op->aa_count = ntohs(1);
dirkx 4:d9f5c4abc5f8 353 p = qA(p,moi_local_name);
dirkx 4:d9f5c4abc5f8 354 break;
dirkx 4:d9f5c4abc5f8 355
dirkx 4:d9f5c4abc5f8 356 case DNS_RRTYPE_SRV: // SRV record and a gratious A record to complete.
dirkx 4:d9f5c4abc5f8 357 op->aa_count = ntohs(moi_txt ? 2 : 1);
dirkx 4:d9f5c4abc5f8 358 p = qSRV(p,moi_local_pglue);
dirkx 4:d9f5c4abc5f8 359
dirkx 4:d9f5c4abc5f8 360 p = mPTR(p,moi_local_proto, moi_local_pglue);
dirkx 4:d9f5c4abc5f8 361 if (moi_txt && * moi_txt)
dirkx 4:d9f5c4abc5f8 362 p = mTXT(p,moi_local_pglue,moi_txt);
dirkx 4:d9f5c4abc5f8 363 break;
dirkx 4:d9f5c4abc5f8 364 }
dirkx 4:d9f5c4abc5f8 365 p = mARR(p,moi_local_name,moi_ip);
dirkx 4:d9f5c4abc5f8 366 m_pUDPSocket->sendto(out,p-out,&dst);
dirkx 4:d9f5c4abc5f8 367 DBG("Reply type %d sent to %s\r\n",t,dst);
dirkx 4:d9f5c4abc5f8 368 }
dirkx 4:d9f5c4abc5f8 369
dirkx 4:d9f5c4abc5f8 370 char * mDNSResponder::decodeQBlock(char * udp, int len, char *p, char * fqdn, int fqdn_size, uint32_t *Qclass, uint32_t *Qtype) {
dirkx 4:d9f5c4abc5f8 371 char * endp = udp + len;
dirkx 4:d9f5c4abc5f8 372 int depth = 0;
dirkx 4:d9f5c4abc5f8 373 int l, ll = 0;
dirkx 4:d9f5c4abc5f8 374 char * q = 0;
dirkx 4:d9f5c4abc5f8 375 char * ep = fqdn;
dirkx 4:d9f5c4abc5f8 376
dirkx 4:d9f5c4abc5f8 377 do {
dirkx 4:d9f5c4abc5f8 378 while (((l = *p++) < 192) && (l > 0)) {
dirkx 4:d9f5c4abc5f8 379 if (p + l >= endp) {
dirkx 4:d9f5c4abc5f8 380 DBG("Malformed packet or bug, RR field larger than packet itself\n\r");
dirkx 4:d9f5c4abc5f8 381 return NULL;
dirkx 4:d9f5c4abc5f8 382 };
dirkx 4:d9f5c4abc5f8 383
dirkx 4:d9f5c4abc5f8 384 if (ll + l + 1 > fqdn_size) {
dirkx 4:d9f5c4abc5f8 385 DBG("Malformed packet or bug, FQDN exceeds %d bytes\n\r", fqdn_size);
dirkx 4:d9f5c4abc5f8 386 return NULL;
dirkx 4:d9f5c4abc5f8 387 }
dirkx 4:d9f5c4abc5f8 388
dirkx 4:d9f5c4abc5f8 389 memcpy(ep,p,l);
dirkx 4:d9f5c4abc5f8 390 ep[l]='.';
dirkx 4:d9f5c4abc5f8 391 ep += l + 1;
dirkx 4:d9f5c4abc5f8 392 p += l;
dirkx 4:d9f5c4abc5f8 393 ll += l + 1;
dirkx 4:d9f5c4abc5f8 394 };
dirkx 4:d9f5c4abc5f8 395
dirkx 4:d9f5c4abc5f8 396 if (l >= 192) {
dirkx 4:d9f5c4abc5f8 397 // construct an offset pointer by wiping the top 1 bits
dirkx 4:d9f5c4abc5f8 398 // and then getting the remaining 8 bytes to make 14.
dirkx 4:d9f5c4abc5f8 399 l -= 192;
dirkx 4:d9f5c4abc5f8 400 l = l << 8;
dirkx 4:d9f5c4abc5f8 401 l += *p++;
dirkx 4:d9f5c4abc5f8 402
dirkx 4:d9f5c4abc5f8 403 // rescue our reference; as we've not gotten the Qt's yet
dirkx 4:d9f5c4abc5f8 404 // and these follow the last entry in our record (and not
dirkx 4:d9f5c4abc5f8 405 // that from the compressed values.
dirkx 4:d9f5c4abc5f8 406 //
dirkx 4:d9f5c4abc5f8 407 if (!q) q = p;
dirkx 4:d9f5c4abc5f8 408
dirkx 4:d9f5c4abc5f8 409 // printf(" [->%d] ",l);
dirkx 4:d9f5c4abc5f8 410 p = udp + l;
dirkx 4:d9f5c4abc5f8 411
dirkx 4:d9f5c4abc5f8 412 if (p >= udp + len || p < udp + 12) {
dirkx 4:d9f5c4abc5f8 413 DBG("Malformed packet or bug, pointer outside UDP packet\n\r");
dirkx 4:d9f5c4abc5f8 414 return NULL;
dirkx 4:d9f5c4abc5f8 415 };
dirkx 4:d9f5c4abc5f8 416 };
dirkx 4:d9f5c4abc5f8 417
dirkx 4:d9f5c4abc5f8 418 if (depth++ >= 128) {
dirkx 4:d9f5c4abc5f8 419 DBG("Malformed packet or bug, depth too high\n\r");
dirkx 4:d9f5c4abc5f8 420 return NULL;
dirkx 4:d9f5c4abc5f8 421 };
dirkx 4:d9f5c4abc5f8 422 } while (l);
dirkx 4:d9f5c4abc5f8 423
dirkx 4:d9f5c4abc5f8 424 // Terminate the FQDN string.
dirkx 4:d9f5c4abc5f8 425 *ep = 0;
dirkx 4:d9f5c4abc5f8 426
dirkx 4:d9f5c4abc5f8 427 // in case no compression was used at all.
dirkx 4:d9f5c4abc5f8 428 if (!q)
dirkx 4:d9f5c4abc5f8 429 q = p;
dirkx 4:d9f5c4abc5f8 430
dirkx 4:d9f5c4abc5f8 431 *Qtype = htons(q[0] + q[1]*256);
dirkx 4:d9f5c4abc5f8 432 *Qclass = htons(q[2] + q[3]*256);
dirkx 4:d9f5c4abc5f8 433 return p;
dirkx 4:d9f5c4abc5f8 434 }
dirkx 4:d9f5c4abc5f8 435
dirkx 4:d9f5c4abc5f8 436 void mDNSResponder::onUDPSocketEvent(UDPSocketEvent e) {
dirkx 4:d9f5c4abc5f8 437 char udp[ 1500 ];
dirkx 4:d9f5c4abc5f8 438 Host from;
dirkx 4:d9f5c4abc5f8 439 int len;
dirkx 4:d9f5c4abc5f8 440
dirkx 4:d9f5c4abc5f8 441 //The only event for now
dirkx 4:d9f5c4abc5f8 442 if (e != UDPSOCKET_READABLE)
dirkx 4:d9f5c4abc5f8 443 return;
dirkx 4:d9f5c4abc5f8 444
dirkx 4:d9f5c4abc5f8 445 // parse through the packet; find any PTR requests
dirkx 4:d9f5c4abc5f8 446 // and respond to any for _http._tcp._local.
dirkx 4:d9f5c4abc5f8 447 //
dirkx 4:d9f5c4abc5f8 448 while ((len = m_pUDPSocket->recvfrom( (char*)&udp, sizeof(udp), &from )) != 0) {
dirkx 4:d9f5c4abc5f8 449 DNSPacket * dp = (DNSPacket *) udp;
dirkx 4:d9f5c4abc5f8 450
dirkx 4:d9f5c4abc5f8 451 unsigned int tid = ntohs(dp->tid);
dirkx 4:d9f5c4abc5f8 452 unsigned int flags = ntohs(dp->flags);
dirkx 4:d9f5c4abc5f8 453 unsigned int nQ = ntohs(dp->question_count);
dirkx 4:d9f5c4abc5f8 454
dirkx 4:d9f5c4abc5f8 455 if (flags & 2 != 0 || nQ < 1)
dirkx 4:d9f5c4abc5f8 456 continue; // we only want questions
dirkx 4:d9f5c4abc5f8 457
dirkx 4:d9f5c4abc5f8 458 // assume nQ NON terminated fields followed by Qtype & Qclass
dirkx 4:d9f5c4abc5f8 459 //
dirkx 4:d9f5c4abc5f8 460 char * p = udp + 12;
dirkx 4:d9f5c4abc5f8 461 for (int i = 0; i < nQ; i++) {
dirkx 4:d9f5c4abc5f8 462 char fqdn[ 256 ];
dirkx 4:d9f5c4abc5f8 463 uint32_t Qt, Qc;
dirkx 4:d9f5c4abc5f8 464
dirkx 4:d9f5c4abc5f8 465 if ( (p = decodeQBlock(udp,len,p,fqdn,sizeof(fqdn),&Qc, &Qt)) == 0)
dirkx 4:d9f5c4abc5f8 466 return;
dirkx 4:d9f5c4abc5f8 467
dirkx 4:d9f5c4abc5f8 468 // We only deal with INternet.
dirkx 4:d9f5c4abc5f8 469 //
dirkx 4:d9f5c4abc5f8 470 if (Qc != DNS_RRCLASS_IN)
dirkx 4:d9f5c4abc5f8 471 continue;
dirkx 4:d9f5c4abc5f8 472
dirkx 4:d9f5c4abc5f8 473 DBG("IN query %x for %s\n\r", Qt, fqdn);
dirkx 4:d9f5c4abc5f8 474
dirkx 4:d9f5c4abc5f8 475 // Normally we'll respond to a mCast query for the PTR of our conceptual
dirkx 4:d9f5c4abc5f8 476 // service; to which we reply with the services we run; and then the A
dirkx 4:d9f5c4abc5f8 477 // records for our actual endpoint. However if one of the requistors their
dirkx 4:d9f5c4abc5f8 478 // cashing is not up to scratch - we may (also) get hit up a bit later for
dirkx 4:d9f5c4abc5f8 479 // the secondary records under their logical names. So we respond to
dirkx 4:d9f5c4abc5f8 480 // all 3. As this is likely to happen due to resource constraints on the
dirkx 4:d9f5c4abc5f8 481 // side of the requestor; we are careful and reply as 'narrow' as possible.
dirkx 4:d9f5c4abc5f8 482 //
dirkx 4:d9f5c4abc5f8 483 // Note that we also respond to the ANY query - as to make a quick 'dig'
dirkx 4:d9f5c4abc5f8 484 // testing command easier.
dirkx 4:d9f5c4abc5f8 485 //
dirkx 4:d9f5c4abc5f8 486 if ((Qt == DNS_RRTYPE_PTR || Qt == 255) && !(strcmp(fqdn,moi_local_proto)))
dirkx 4:d9f5c4abc5f8 487 sendReply(DNS_RRTYPE_PTR,tid,from);
dirkx 4:d9f5c4abc5f8 488 else if ((Qt == DNS_RRTYPE_A || Qt == 255) && !(strcmp(fqdn,moi_local_name)))
dirkx 4:d9f5c4abc5f8 489 sendReply(DNS_RRTYPE_A,tid,from);
dirkx 4:d9f5c4abc5f8 490 else if ((Qt == DNS_RRTYPE_SRV || Qt == 255) && !(strcmp(fqdn,moi_local_pglue)))
dirkx 4:d9f5c4abc5f8 491 sendReply(DNS_RRTYPE_SRV,tid,from);
dirkx 4:d9f5c4abc5f8 492 else
dirkx 4:d9f5c4abc5f8 493 DBG(".. which was ignored\n\r", Qt, fqdn);
dirkx 4:d9f5c4abc5f8 494
dirkx 4:d9f5c4abc5f8 495 };
dirkx 4:d9f5c4abc5f8 496 }
dirkx 4:d9f5c4abc5f8 497 }
dirkx 4:d9f5c4abc5f8 498 #endif