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

Dependencies:   mbed

Committer:
dirkx
Date:
Tue Jul 27 17:22:17 2010 +0000
Revision:
3:e1d86543ec50
Parent:
2:816cbd922d3e
Child:
4:d9f5c4abc5f8

        

Who changed what in which revision?

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