Dirk-Willem van Gulik (NXP/mbed) / Mbed 2 deprecated Bonjour

Dependencies:   mbed

Committer:
dirkx
Date:
Sat Jul 24 20:59:52 2010 +0000
Revision:
2:816cbd922d3e
Parent:
1:59820ca5c83a
Child:
3:e1d86543ec50

        

Who changed what in which revision?

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