Bonjour/mDNS lib, works with the new network stack

Fork of BonjourLib by Dirk-Willem van Gulik (NXP/mbed)

Committer:
Jasper
Date:
Fri May 30 09:43:56 2014 +0000
Revision:
3:b8a78d6da192
Parent:
2:18d443d86057
fix A records. some more debugging.

Who changed what in which revision?

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