├── .gitignore ├── Makefile ├── README.md ├── docs ├── pres │ ├── 260px-Openbsd.png │ ├── index.html │ ├── mdns.mgp │ ├── mgp00001.html │ ├── mgp00001.idx.jpg │ ├── mgp00001.jpg │ ├── mgp00001.txt │ ├── mgp00002.html │ ├── mgp00002.idx.jpg │ ├── mgp00002.jpg │ ├── mgp00002.txt │ ├── mgp00003.html │ ├── mgp00003.idx.jpg │ ├── mgp00003.jpg │ ├── mgp00003.txt │ ├── mgp00004.html │ ├── mgp00004.idx.jpg │ ├── mgp00004.jpg │ ├── mgp00004.txt │ ├── mgp00005.html │ ├── mgp00005.idx.jpg │ ├── mgp00005.jpg │ ├── mgp00005.txt │ ├── mgp00006.html │ ├── mgp00006.idx.jpg │ ├── mgp00006.jpg │ ├── mgp00006.txt │ ├── mgp00007.html │ ├── mgp00007.idx.jpg │ ├── mgp00007.jpg │ ├── mgp00007.txt │ ├── mgp00008.html │ ├── mgp00008.idx.jpg │ ├── mgp00008.jpg │ ├── mgp00008.txt │ ├── mgp00009.html │ ├── mgp00009.idx.jpg │ ├── mgp00009.jpg │ ├── mgp00009.txt │ ├── mgp00010.html │ ├── mgp00010.idx.jpg │ ├── mgp00010.jpg │ ├── mgp00010.txt │ ├── mgp00011.html │ ├── mgp00011.idx.jpg │ ├── mgp00011.jpg │ ├── mgp00011.txt │ ├── mgp00012.html │ ├── mgp00012.idx.jpg │ ├── mgp00012.jpg │ ├── mgp00012.txt │ ├── mgp00013.html │ ├── mgp00013.idx.jpg │ ├── mgp00013.jpg │ ├── mgp00013.txt │ ├── mgp00014.html │ ├── mgp00014.idx.jpg │ ├── mgp00014.jpg │ ├── mgp00014.txt │ ├── mgp00015.html │ ├── mgp00015.idx.jpg │ ├── mgp00015.jpg │ ├── mgp00015.txt │ ├── mgp00016.html │ ├── mgp00016.idx.jpg │ ├── mgp00016.jpg │ ├── mgp00016.txt │ ├── mgp00017.html │ ├── mgp00017.idx.jpg │ ├── mgp00017.jpg │ ├── mgp00017.txt │ ├── mgp00018.html │ ├── mgp00018.idx.jpg │ ├── mgp00018.jpg │ ├── mgp00018.txt │ ├── mgp00019.html │ ├── mgp00019.idx.jpg │ ├── mgp00019.jpg │ ├── mgp00019.txt │ ├── mgp00020.html │ ├── mgp00020.idx.jpg │ ├── mgp00020.jpg │ ├── mgp00020.txt │ ├── mgp00021.html │ ├── mgp00021.idx.jpg │ ├── mgp00021.jpg │ ├── mgp00021.txt │ ├── mgp00022.html │ ├── mgp00022.idx.jpg │ ├── mgp00022.jpg │ ├── mgp00022.txt │ ├── mgp00023.html │ ├── mgp00023.idx.jpg │ ├── mgp00023.jpg │ ├── mgp00023.txt │ └── openbsd_puffy.png ├── rfc1035.txt ├── rfc3845.txt ├── rfc6762.txt └── rfc6763.txt ├── libmdns ├── Makefile ├── mdnsl.c └── shlib_version ├── mdnsctl ├── Makefile ├── mdnsctl.8 ├── mdnsctl.c ├── parser.c └── parser.h ├── mdnsd ├── Makefile ├── control.c ├── control.h ├── interface.c ├── kiface.c ├── log.c ├── log.h ├── mdns.c ├── mdns.h ├── mdnsd.8 ├── mdnsd.c ├── mdnsd.h └── packet.c ├── mkbuild └── version.h /.gitignore: -------------------------------------------------------------------------------- 1 | mdnsctl/mdnsctl 2 | mdnsd/mdnsd 3 | *.o 4 | *.manlint 5 | cscope.* 6 | test 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SUBDIR= libmdns mdnsctl mdnsd 2 | 3 | .include 4 | 5 | TAG_SUBDIRS+=mdnsd 6 | TAG_SUBDIRS+=mdnsctl 7 | TAG_SUBDIRS+=/usr/include 8 | TAG_SUBDIRS+=/usr/src/lib/libevent 9 | 10 | etags: 11 | find ${TAG_SUBDIRS} -type f -iname "*.[ch]" | \ 12 | etags -o TAGS - 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Christiano F. Haesbaert 2 | 3 | # Multicast Domain Name System for OpenBSD 4 | 5 | ## Quickstart 6 | 7 | If you're looking for a quickstart jump to the end of this document. 8 | 9 | ## Intro 10 | 11 | This is an attempt to bring native mdns/dns-sd to OpenBSD. Mainly cause all the other options suck and proper network browsing is a nice feature these days. 12 | 13 | My goal is to first provide a solid mdns framework without the service-discovery capabilities which are much more complex. When that is working properly, work on service-discovery will begin, the architecture was designed in order to support it. So goals: 14 | 15 | * Have a mdns responder/querier as an user process (`mdnsd`). 16 | * Have integration with libc's resolver, read: make `gethostbyname` and friends resolve names through mdns. 17 | * Have an application interface so other software can publish names/services as they see fit. 18 | * Have a mdns control program, which is mainly a crude interface to the API. 19 | 20 | ## MDNSD Design 21 | 22 | The "Multicast Domain Name System Daemon" is an user process that runs without privileges, it binds to udp port 5353 and acts as the querier/responder for all mdns requests. By responder we understand who is responsible for answering mdns queries, and by querier the other way around, read: This is different from libc's unicast resolver, we *NEED* to cache answers and maintain state. 23 | 24 | As most OpenBSD daemons, it drops privilege upon startup and none task requires super-user privilege. All work is done on a single process, my first design had a process per interface, but that became overkill and overcomplex. 25 | 26 | The API is designed above Henning Brauer `imsg` framework, so we have a unix domain socket that listen to requests from other processes, much like `ripctl` and `ospfctl` do, but we need a fancier API. We use libevent and all it's glorious features to have a proper unix daemon. 27 | 28 | There is a routing socket in order to be notified when link goes up and down, or when an interface address changes, this is *required* in order to publish records, every time link comes up we need to re-probe for our records and things like that, we use as our main name the short name from /etc/myname in the .local domain. 29 | 30 | The basic data flow would be: 31 | 32 | __________ _______ 33 | | Programs | <--Control Socket (API)--> | MDNSD | <-- Mcast Packets --> 34 | ---------- ------- 35 | 36 | ## LIBMDNS Design (API) 37 | 38 | Libmdns is a shared library in which programs can link against in order to have mdns capabilities, like publishing services, browsing the network and so on, by now you can lookup resources, browse and publish services. All the library does is sending and receiving messages to `mdnsd` through the imsg framework. The library should provides: 39 | 40 | * Means for looking up names. (DONE) 41 | * Means for publishing names. (DONE) 42 | * Means for browsing services (dns-service-discovery). (DONE) 43 | * Means for publishing services. (DONE) 44 | 45 | By now no library is being used to make it easier for people to test `mdnsctl` (read no shared objecto), everything is being kept on `mdnsl.c` in `mdnsctl/`. 46 | 47 | On libc integration: 48 | 49 | After a chat with nicm@ we have decided not to worry about libc right now, maybe never. See the README file on mdns-libc branch if you're curious. 50 | 51 | ## MDNSCTL 52 | 53 | It's a simple interface for the library, code is inspired in `ripctl`. By now you can use it to lookup hosts, and browse and publish services. 54 | 55 | ## How do I use this thing ? 56 | 57 | Install it from openbsd ports (net/openmdns) 58 | 59 | Run `mdnsd` on the desired interface: `mdnsd -d rl0` 60 | 61 | Play with `mdnsctl`: 62 | 63 | 64 | # Lookup a host as well as the HINFO record 65 | mdnsctl lookup -h foobar.local 66 | # Reverse lookup an address 67 | mdnsctl rlookup 192.168.8.32 68 | # Browse up all services in the local network 69 | mdnsctl browse 70 | # Browse and resolve all services 71 | mdnsctl browse -r 72 | # Browse and resolve all the http services in the local network 73 | mdnsctl browse -r http tcp 74 | # Publish a simple ftp service 75 | mdnsctl publish myftp ftp tcp 21 "user=foobar" 76 | # Proxy publish a https service that has www.mysite.com as the target 77 | mdnsctl proxy mysite https tcp 443 www.mysite.com 12.3.45.6 "user=foobar" 78 | 79 | -------------------------------------------------------------------------------- /docs/pres/260px-Openbsd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/260px-Openbsd.png -------------------------------------------------------------------------------- /docs/pres/index.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | Page 1 5 | Page 2 6 | Page 3 7 | Page 4 8 | Page 5 9 | Page 6 10 | Page 7 11 | Page 8 12 | Page 9 13 | Page 10 14 | Page 11 15 | Page 12 16 | Page 13 17 | Page 14 18 | Page 15 19 | Page 16 20 | Page 17 21 | Page 18 22 | Page 19 23 | Page 20 24 | Page 21 25 | Page 22 26 | Page 23 27 |
28 | Generated by MagicPoint 29 |
30 | 31 | -------------------------------------------------------------------------------- /docs/pres/mdns.mgp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mdns.mgp -------------------------------------------------------------------------------- /docs/pres/mgp00001.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 1: MDNS
6 |
7 | Page 1
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00001.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00001.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00001.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00001.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00001.txt -------------------------------------------------------------------------------- /docs/pres/mgp00002.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 2: MDNS
6 |
7 | Page 2
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00002.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00002.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00002.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00002.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00002.txt -------------------------------------------------------------------------------- /docs/pres/mgp00003.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 3: Por que MDNS ?
6 |
7 | Page 3
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00003.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00003.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00003.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00003.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00003.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00003.txt -------------------------------------------------------------------------------- /docs/pres/mgp00004.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00004.html -------------------------------------------------------------------------------- /docs/pres/mgp00004.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00004.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00004.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00004.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00004.txt -------------------------------------------------------------------------------- /docs/pres/mgp00005.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00005.html -------------------------------------------------------------------------------- /docs/pres/mgp00005.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00005.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00005.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00005.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00005.txt -------------------------------------------------------------------------------- /docs/pres/mgp00006.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 6: Funcionamento com DNS-SD
6 |
7 | Page 6
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00006.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00006.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00006.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00006.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00006.txt -------------------------------------------------------------------------------- /docs/pres/mgp00007.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 7: Eu gosto de exemplos...
6 |
7 | Page 7
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00007.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00007.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00007.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00007.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00007.txt -------------------------------------------------------------------------------- /docs/pres/mgp00008.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 8: Ainda nos exemplos...
6 |
7 | Page 8
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00008.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00008.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00008.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00008.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00008.txt -------------------------------------------------------------------------------- /docs/pres/mgp00009.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00009.html -------------------------------------------------------------------------------- /docs/pres/mgp00009.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00009.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00009.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00009.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00009.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00009.txt -------------------------------------------------------------------------------- /docs/pres/mgp00010.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00010.html -------------------------------------------------------------------------------- /docs/pres/mgp00010.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00010.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00010.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00010.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00010.txt -------------------------------------------------------------------------------- /docs/pres/mgp00011.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00011.html -------------------------------------------------------------------------------- /docs/pres/mgp00011.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00011.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00011.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00011.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00011.txt -------------------------------------------------------------------------------- /docs/pres/mgp00012.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 12: Freedesktop's Avahi
6 |
7 | Page 12
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00012.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00012.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00012.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00012.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00012.txt: -------------------------------------------------------------------------------- 1 | 2 | Freedesktop's Avahi 3 | Popular no Linux. 4 | Implementa todo Zeroconf. 5 | Relativamente portavel. 6 | API compativel com bonjour. 7 | 8 | ~57000 linhas. 9 | Licensa LGPL. 10 | API complexa. 11 | Muitas dependencias. 12 | Tipico codigo pseudo-OO dos gtk-folks. 13 | DBUS. 14 | -------------------------------------------------------------------------------- /docs/pres/mgp00013.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 13: Apple Mdns (Bonjour):
6 |
7 | Page 13
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00013.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00013.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00013.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00013.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00013.txt: -------------------------------------------------------------------------------- 1 | 2 | Apple Mdns (Bonjour): 3 | Primeira implementacao. 4 | Escrita pelo criador do protocolo. 5 | Utilizada no OSX e NetBSD. 6 | 7 | Licensa Apache 2. 8 | API complexa. 9 | Tipico codigo corporativo. 10 | Codigo bloated. 11 | -------------------------------------------------------------------------------- /docs/pres/mgp00014.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 14: Por que criar o OpenMdns ?
6 |
7 | Page 14
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00014.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00014.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00014.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00014.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00014.txt -------------------------------------------------------------------------------- /docs/pres/mgp00015.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 15: O Openmdns
6 |
7 | Page 15
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00015.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00015.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00015.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00015.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00015.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00015.txt -------------------------------------------------------------------------------- /docs/pres/mgp00016.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 16: Mdnsd, o daemon.
6 |
7 | Page 16
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00016.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00016.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00016.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00016.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00016.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00016.txt -------------------------------------------------------------------------------- /docs/pres/mgp00017.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 17: Mdnsctl, o controller.
6 |
7 | Page 17
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00017.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00017.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00017.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00017.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00017.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00017.txt -------------------------------------------------------------------------------- /docs/pres/mgp00018.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 18: As mensagens...
6 |
7 | Page 18
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00018.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00018.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00018.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00018.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00018.txt: -------------------------------------------------------------------------------- 1 | 2 | As mensagens... 3 | 4 | struct mdns_msg_lkup { /* IMSG_CTL_LOOKUP */ 5 | char dname[MAXHOSTNAMELEN]; 6 | u_int16_t type; 7 | u_int16_t class; 8 | }; 9 | 10 | struct mdns_msg_browse { /* IMSG_CTL_BROWSER_ADD|DEL */ 11 | char dname[MAXHOSTNAMELEN]; /* request/reply */ 12 | char ptr[MAXHOSTNAMELEN]; /* reply */ 13 | int up; /* reply */ 14 | }; 15 | -------------------------------------------------------------------------------- /docs/pres/mgp00019.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 19: Libmdns
6 |
7 | Page 19
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00019.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00019.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00019.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00019.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00019.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00019.txt -------------------------------------------------------------------------------- /docs/pres/mgp00020.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 20: API
6 |
7 | Page 20
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00020.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00020.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00020.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00020.txt: -------------------------------------------------------------------------------- 1 | 2 | API 3 | 4 | Resolver 5 | int mdns_resolver_init(struct mdns_resolver *); 6 | void mdns_resolver_finish(struct mdns_resolver *); 7 | int mdns_resolver_host(struct mdns_resolver *, const char *, struct in_addr *); 8 | int mdns_resolver_hinfo(struct mdns_resolver *, const char *, struct hinfo *); 9 | 10 | Browser 11 | int mdns_browser_init(struct mdns_browser *, void (*cb)(int, const char *, void *); 12 | void mdns_browser_finish(struct mdns_browser *); 13 | int mdns_browser_add_proto(struct mdns_browser *, const char *); 14 | int mdns_browser_del_proto(struct mdns_browser *, const char *); 15 | int mdns_browser_pending(struct mdns_browser *); 16 | int mdns_browser_fetch(struct mdns_browser *); 17 | -------------------------------------------------------------------------------- /docs/pres/mgp00021.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 21: Colaborando
6 |
7 | Page 21
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00021.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00021.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00021.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00021.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00021.txt: -------------------------------------------------------------------------------- 1 | 2 | Colaborando 3 | 4 | http://github.com/haesbaert/mdnsd 5 | 6 | Testando, em especial em uma rede grande. 7 | Testando em arquiteturas obscuras (alpha/hppa/sparc64...). 8 | Mandando diffs, em especial re-escrever o parser dos pacotes. 9 | Reportando bugs. 10 | 11 | Mandando um email ao autor dizendo que gostaram do projeto :-). 12 | Usando e divulgando OpenBSD. 13 | Comprando as releases do OpenBSD. 14 | -------------------------------------------------------------------------------- /docs/pres/mgp00022.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 22: Drafts
6 |
7 | Page 22
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00022.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00022.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00022.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00022.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00022.txt: -------------------------------------------------------------------------------- 1 | 2 | Drafts 3 | 4 | MDNS 5 | http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt 6 | 7 | DNS-SD 8 | http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt 9 | 10 | DNS 11 | www.ietf.org/rfc/rfc1035.txt 12 | 13 | -------------------------------------------------------------------------------- /docs/pres/mgp00023.html: -------------------------------------------------------------------------------- 1 | 2 | MagicPoint presentation foils 3 | 4 | [index] [text page] [<<start] [<prev] [next>] [last>>] 5 |
Page 23: Perguntas ?
6 |
7 | Page 23
8 |
Generated by MagicPoint 9 | 10 | -------------------------------------------------------------------------------- /docs/pres/mgp00023.idx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00023.idx.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00023.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/mgp00023.jpg -------------------------------------------------------------------------------- /docs/pres/mgp00023.txt: -------------------------------------------------------------------------------- 1 | 2 | Perguntas ? 3 | 4 | 5 | Email: haesbaert@haesbaert.org 6 | 7 | MSN: cartucho@cartucho.org 8 | 9 | IRC: haesbaert at irc.freenode.net 10 | SILC: haesbaert at peereboom.us #openbsd 11 | 12 | MDNS: http://github.com/haesbaert/mdnsd 13 | http://haesbaert.org/upload/mdns_pres 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/pres/openbsd_puffy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haesbaert/mdnsd/acab252991f29e8b53b62ccf7c2d222312837ac8/docs/pres/openbsd_puffy.png -------------------------------------------------------------------------------- /docs/rfc3845.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Network Working Group J. Schlyter, Ed. 8 | Request for Comments: 3845 August 2004 9 | Updates: 3755, 2535 10 | Category: Standards Track 11 | 12 | 13 | DNS Security (DNSSEC) NextSECure (NSEC) RDATA Format 14 | 15 | Status of this Memo 16 | 17 | This document specifies an Internet standards track protocol for the 18 | Internet community, and requests discussion and suggestions for 19 | improvements. Please refer to the current edition of the "Internet 20 | Official Protocol Standards" (STD 1) for the standardization state 21 | and status of this protocol. Distribution of this memo is unlimited. 22 | 23 | Copyright Notice 24 | 25 | Copyright (C) The Internet Society (2004). 26 | 27 | Abstract 28 | 29 | This document redefines the wire format of the "Type Bit Map" field 30 | in the DNS NextSECure (NSEC) resource record RDATA format to cover 31 | the full resource record (RR) type space. 32 | 33 | Table of Contents 34 | 35 | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 36 | 2. The NSEC Resource Record . . . . . . . . . . . . . . . . . . . 2 37 | 2.1. NSEC RDATA Wire Format . . . . . . . . . . . . . . . . . 3 38 | 2.1.1. The Next Domain Name Field . . . . . . . . . . . 3 39 | 2.1.2. The List of Type Bit Map(s) Field . . . . . . . 3 40 | 2.1.3. Inclusion of Wildcard Names in NSEC RDATA . . . 4 41 | 2.2. The NSEC RR Presentation Format . . . . . . . . . . . . 4 42 | 2.3. NSEC RR Example . . . . . . . . . . . . . . . . . . . . 5 43 | 3. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 5 44 | 4. Security Considerations . . . . . . . . . . . . . . . . . . . 5 45 | 5. References . . . . . . . . . . . . . . . . . . . . . . . . . . 6 46 | 5.1. Normative References . . . . . . . . . . . . . . . . . . 6 47 | 5.2. Informative References . . . . . . . . . . . . . . . . . 6 48 | 6. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 6 49 | 7. Author's Address . . . . . . . . . . . . . . . . . . . . . . . 6 50 | 8. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 7 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Schlyter, Ed. Standards Track [Page 1] 59 | 60 | RFC 3845 DNSSEC NSEC RDATA Format August 2004 61 | 62 | 63 | 1. Introduction 64 | 65 | The DNS [6][7] NSEC [5] Resource Record (RR) is used for 66 | authenticated proof of the non-existence of DNS owner names and 67 | types. The NSEC RR is based on the NXT RR as described in RFC 2535 68 | [2], and is similar except for the name and typecode. The RDATA 69 | format for the NXT RR has the limitation in that the RDATA could only 70 | carry information about the existence of the first 127 types. RFC 71 | 2535 did reserve a bit to specify an extension mechanism, but the 72 | mechanism was never actually defined. 73 | 74 | In order to avoid needing to develop an extension mechanism into a 75 | deployed base of DNSSEC aware servers and resolvers once the first 76 | 127 type codes are allocated, this document redefines the wire format 77 | of the "Type Bit Map" field in the NSEC RDATA to cover the full RR 78 | type space. 79 | 80 | This document introduces a new format for the type bit map. The 81 | properties of the type bit map format are that it can cover the full 82 | possible range of typecodes, that it is relatively economical in the 83 | amount of space it uses for the common case of a few types with an 84 | owner name, that it can represent owner names with all possible types 85 | present in packets of approximately 8.5 kilobytes, and that the 86 | representation is simple to implement. Efficient searching of the 87 | type bitmap for the presence of certain types is not a requirement. 88 | 89 | For convenience and completeness, this document presents the syntax 90 | and semantics for the NSEC RR based on the specification in RFC 2535 91 | [2] and as updated by RFC 3755 [5], thereby not introducing changes 92 | except for the syntax of the type bit map. 93 | 94 | This document updates RFC 2535 [2] and RFC 3755 [5]. 95 | 96 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 97 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 98 | document are to be interpreted as described in BCP 14, RFC 2119 [1]. 99 | 100 | 2. The NSEC Resource Record 101 | 102 | The NSEC resource record lists two separate things: the owner name of 103 | the next RRset in the canonical ordering of the zone, and the set of 104 | RR types present at the NSEC RR's owner name. The complete set of 105 | NSEC RRs in a zone indicate which RRsets exist in a zone, and form a 106 | chain of owner names in the zone. This information is used to 107 | provide authenticated denial of existence for DNS data, as described 108 | in RFC 2535 [2]. 109 | 110 | The type value for the NSEC RR is 47. 111 | 112 | 113 | 114 | Schlyter, Ed. Standards Track [Page 2] 115 | 116 | RFC 3845 DNSSEC NSEC RDATA Format August 2004 117 | 118 | 119 | The NSEC RR RDATA format is class independent and defined for all 120 | classes. 121 | 122 | The NSEC RR SHOULD have the same TTL value as the SOA minimum TTL 123 | field. This is in the spirit of negative caching [8]. 124 | 125 | 2.1. NSEC RDATA Wire Format 126 | 127 | The RDATA of the NSEC RR is as shown below: 128 | 129 | 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 130 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 131 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 132 | / Next Domain Name / 133 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 134 | / List of Type Bit Map(s) / 135 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 136 | 137 | 2.1.1. The Next Domain Name Field 138 | 139 | The Next Domain Name field contains the owner name of the next RR in 140 | the canonical ordering of the zone. The value of the Next Domain 141 | Name field in the last NSEC record in the zone is the name of the 142 | zone apex (the owner name of the zone's SOA RR). 143 | 144 | A sender MUST NOT use DNS name compression on the Next Domain Name 145 | field when transmitting an NSEC RR. 146 | 147 | Owner names of RRsets that are not authoritative for the given zone 148 | (such as glue records) MUST NOT be listed in the Next Domain Name 149 | unless at least one authoritative RRset exists at the same owner 150 | name. 151 | 152 | 2.1.2. The List of Type Bit Map(s) Field 153 | 154 | The RR type space is split into 256 window blocks, each representing 155 | the low-order 8 bits of the 16-bit RR type space. Each block that 156 | has at least one active RR type is encoded using a single octet 157 | window number (from 0 to 255), a single octet bitmap length (from 1 158 | to 32) indicating the number of octets used for the window block's 159 | bitmap, and up to 32 octets (256 bits) of bitmap. 160 | 161 | Window blocks are present in the NSEC RR RDATA in increasing 162 | numerical order. 163 | 164 | "|" denotes concatenation 165 | 166 | Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) + 167 | 168 | 169 | 170 | Schlyter, Ed. Standards Track [Page 3] 171 | 172 | RFC 3845 DNSSEC NSEC RDATA Format August 2004 173 | 174 | 175 | Each bitmap encodes the low-order 8 bits of RR types within the 176 | window block, in network bit order. The first bit is bit 0. For 177 | window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds 178 | to RR type 2 (NS), and so forth. For window block 1, bit 1 179 | corresponds to RR type 257, and bit 2 to RR type 258. If a bit is 180 | set to 1, it indicates that an RRset of that type is present for the 181 | NSEC RR's owner name. If a bit is set to 0, it indicates that no 182 | RRset of that type is present for the NSEC RR's owner name. 183 | 184 | Since bit 0 in window block 0 refers to the non-existing RR type 0, 185 | it MUST be set to 0. After verification, the validator MUST ignore 186 | the value of bit 0 in window block 0. 187 | 188 | Bits representing Meta-TYPEs or QTYPEs, as specified in RFC 2929 [3] 189 | (section 3.1), or within the range reserved for assignment only to 190 | QTYPEs and Meta-TYPEs MUST be set to 0, since they do not appear in 191 | zone data. If encountered, they must be ignored upon reading. 192 | 193 | Blocks with no types present MUST NOT be included. Trailing zero 194 | octets in the bitmap MUST be omitted. The length of each block's 195 | bitmap is determined by the type code with the largest numerical 196 | value within that block, among the set of RR types present at the 197 | NSEC RR's owner name. Trailing zero octets not specified MUST be 198 | interpreted as zero octets. 199 | 200 | 2.1.3. Inclusion of Wildcard Names in NSEC RDATA 201 | 202 | If a wildcard owner name appears in a zone, the wildcard label ("*") 203 | is treated as a literal symbol and is treated the same as any other 204 | owner name for purposes of generating NSEC RRs. Wildcard owner names 205 | appear in the Next Domain Name field without any wildcard expansion. 206 | RFC 2535 [2] describes the impact of wildcards on authenticated 207 | denial of existence. 208 | 209 | 2.2. The NSEC RR Presentation Format 210 | 211 | The presentation format of the RDATA portion is as follows: 212 | 213 | The Next Domain Name field is represented as a domain name. 214 | 215 | The List of Type Bit Map(s) Field is represented as a sequence of RR 216 | type mnemonics. When the mnemonic is not known, the TYPE 217 | representation as described in RFC 3597 [4] (section 5) MUST be used. 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | Schlyter, Ed. Standards Track [Page 4] 227 | 228 | RFC 3845 DNSSEC NSEC RDATA Format August 2004 229 | 230 | 231 | 2.3. NSEC RR Example 232 | 233 | The following NSEC RR identifies the RRsets associated with 234 | alfa.example.com. and the next authoritative name after 235 | alfa.example.com. 236 | 237 | alfa.example.com. 86400 IN NSEC host.example.com. A MX RRSIG NSEC 238 | TYPE1234 239 | 240 | The first four text fields specify the name, TTL, Class, and RR type 241 | (NSEC). The entry host.example.com. is the next authoritative name 242 | after alfa.example.com. in canonical order. The A, MX, RRSIG, NSEC, 243 | and TYPE1234 mnemonics indicate there are A, MX, RRSIG, NSEC, and 244 | TYPE1234 RRsets associated with the name alfa.example.com. 245 | 246 | The RDATA section of the NSEC RR above would be encoded as: 247 | 248 | 0x04 'h' 'o' 's' 't' 249 | 0x07 'e' 'x' 'a' 'm' 'p' 'l' 'e' 250 | 0x03 'c' 'o' 'm' 0x00 251 | 0x00 0x06 0x40 0x01 0x00 0x00 0x00 0x03 252 | 0x04 0x1b 0x00 0x00 0x00 0x00 0x00 0x00 253 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 254 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 255 | 0x00 0x00 0x00 0x00 0x20 256 | 257 | Assuming that the resolver can authenticate this NSEC record, it 258 | could be used to prove that beta.example.com does not exist, or could 259 | be used to prove that there is no AAAA record associated with 260 | alfa.example.com. Authenticated denial of existence is discussed in 261 | RFC 2535 [2]. 262 | 263 | 3. IANA Considerations 264 | 265 | This document introduces no new IANA considerations, because all of 266 | the protocol parameters used in this document have already been 267 | assigned by RFC 3755 [5]. 268 | 269 | 4. Security Considerations 270 | 271 | The update of the RDATA format and encoding does not affect the 272 | security of the use of NSEC RRs. 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | Schlyter, Ed. Standards Track [Page 5] 283 | 284 | RFC 3845 DNSSEC NSEC RDATA Format August 2004 285 | 286 | 287 | 5. References 288 | 289 | 5.1. Normative References 290 | 291 | [1] Bradner, S., "Key words for use in RFCs to Indicate Requirement 292 | Levels", BCP 14, RFC 2119, March 1997. 293 | 294 | [2] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 295 | 2535, March 1999. 296 | 297 | [3] Eastlake 3rd, D., Brunner-Williams, E., and B. Manning, "Domain 298 | Name System (DNS) IANA Considerations", BCP 42, RFC 2929, 299 | September 2000. 300 | 301 | [4] Gustafsson, A., "Handling of Unknown DNS Resource Record (RR) 302 | Types", RFC 3597, September 2003. 303 | 304 | [5] Weiler, S., "Legacy Resolver Compatibility for Delegation Signer 305 | (DS)", RFC 3755, May 2004. 306 | 307 | 5.2. Informative References 308 | 309 | [6] Mockapetris, P., "Domain names - concepts and facilities", STD 310 | 13, RFC 1034, November 1987. 311 | 312 | [7] Mockapetris, P., "Domain names - implementation and 313 | specification", STD 13, RFC 1035, November 1987. 314 | 315 | [8] Andrews, M., "Negative Caching of DNS Queries (DNS NCACHE)", RFC 316 | 2308, March 1998. 317 | 318 | 6. Acknowledgements 319 | 320 | The encoding described in this document was initially proposed by 321 | Mark Andrews. Other encodings where proposed by David Blacka and 322 | Michael Graff. 323 | 324 | 7. Author's Address 325 | 326 | Jakob Schlyter (editor) 327 | NIC-SE 328 | Box 5774 329 | Stockholm SE-114 87 330 | Sweden 331 | 332 | EMail: jakob@nic.se 333 | URI: http://www.nic.se/ 334 | 335 | 336 | 337 | 338 | Schlyter, Ed. Standards Track [Page 6] 339 | 340 | RFC 3845 DNSSEC NSEC RDATA Format August 2004 341 | 342 | 343 | 8. Full Copyright Statement 344 | 345 | Copyright (C) The Internet Society (2004). 346 | 347 | This document is subject to the rights, licenses and restrictions 348 | contained in BCP 78, and except as set forth therein, the authors 349 | retain all their rights. 350 | 351 | This document and the information contained herein are provided on an 352 | "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE 353 | REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE 354 | INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR 355 | IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF 356 | THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED 357 | WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 358 | 359 | Intellectual Property 360 | 361 | The IETF takes no position regarding the validity or scope of any 362 | Intellectual Property Rights or other rights that might be claimed to 363 | pertain to the implementation or use of the technology described in 364 | this document or the extent to which any license under such rights 365 | might or might not be available; nor does it represent that it has 366 | made any independent effort to identify any such rights. Information 367 | on the IETF's procedures with respect to rights in IETF Documents can 368 | be found in BCP 78 and BCP 79. 369 | 370 | Copies of IPR disclosures made to the IETF Secretariat and any 371 | assurances of licenses to be made available, or the result of an 372 | attempt made to obtain a general license or permission for the use of 373 | such proprietary rights by implementers or users of this 374 | specification can be obtained from the IETF on-line IPR repository at 375 | http://www.ietf.org/ipr. 376 | 377 | The IETF invites any interested party to bring to its attention any 378 | copyrights, patents or patent applications, or other proprietary 379 | rights that may cover technology that may be required to implement 380 | this standard. Please address the information to the IETF at ietf- 381 | ipr@ietf.org. 382 | 383 | Acknowledgement 384 | 385 | Funding for the RFC Editor function is currently provided by the 386 | Internet Society. 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | Schlyter, Ed. Standards Track [Page 7] 395 | 396 | -------------------------------------------------------------------------------- /libmdns/Makefile: -------------------------------------------------------------------------------- 1 | LIB= mdns 2 | SRCS+= mdnsl.c 3 | 4 | CFLAGS+= -g -Wall 5 | CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes 6 | CFLAGS+= -Wmissing-declarations 7 | CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual 8 | CFLAGS+= -Wsign-compare 9 | CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../mdnsd 10 | 11 | .include 12 | -------------------------------------------------------------------------------- /libmdns/mdnsl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Christiano F. Haesbaert 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include "../mdnsd/mdnsd.h" 37 | #include "mdns.h" 38 | 39 | static int mdns_connect(void); 40 | static int mdns_lookup_do(struct mdns *, const char [MAXHOSTNAMELEN], 41 | u_int16_t, u_int16_t); 42 | static int ibuf_send_imsg(struct imsgbuf *, u_int32_t, 43 | void *, u_int16_t); 44 | static int splitdname(char [MAXHOSTNAMELEN], char [MAXHOSTNAMELEN], 45 | char [MAXLABEL], char [4], int *); 46 | static int imsgctl_to_event(int); 47 | 48 | static int mdns_browse_adddel(struct mdns *, const char *, const char *, u_int); 49 | static int mdns_handle_lookup(struct mdns *, struct rr *, int); 50 | static int mdns_handle_browse(struct mdns *, struct rr *, int); 51 | static int mdns_handle_resolve(struct mdns *, struct mdns_service *, int); 52 | static int mdns_handle_group(struct mdns *, char [MAXHOSTNAMELEN], int); 53 | 54 | int 55 | mdns_open(struct mdns *m) 56 | { 57 | int sockfd; 58 | 59 | bzero(m, sizeof(*m)); 60 | if ((sockfd = mdns_connect()) == -1) 61 | return (-1); 62 | imsg_init(&m->ibuf, sockfd); 63 | 64 | return (sockfd); 65 | } 66 | 67 | void 68 | mdns_close(struct mdns *m) 69 | { 70 | imsg_clear(&m->ibuf); 71 | } 72 | 73 | void 74 | mdns_set_lookup_A_hook(struct mdns *m, lookup_A_hook lhk) 75 | { 76 | m->lhk_A = lhk; 77 | } 78 | 79 | void 80 | mdns_set_lookup_PTR_hook(struct mdns *m, lookup_PTR_hook lhk) 81 | { 82 | m->lhk_PTR = lhk; 83 | } 84 | 85 | void 86 | mdns_set_lookup_HINFO_hook(struct mdns *m, lookup_HINFO_hook hhk) 87 | { 88 | m->lhk_HINFO = hhk; 89 | } 90 | 91 | void 92 | mdns_set_browse_hook(struct mdns *m, browse_hook bhk) 93 | { 94 | m->bhk = bhk; 95 | } 96 | 97 | void 98 | mdns_set_resolve_hook(struct mdns *m, resolve_hook rhk) 99 | { 100 | m->rhk = rhk; 101 | } 102 | 103 | void 104 | mdns_set_udata(struct mdns *m, void *udata) 105 | { 106 | m->udata = udata; 107 | } 108 | 109 | void 110 | mdns_set_group_hook(struct mdns *m, group_hook ghk) 111 | { 112 | m->ghk = ghk; 113 | } 114 | 115 | int 116 | mdns_lookup_A(struct mdns *m, const char *host) 117 | { 118 | return (mdns_lookup_do(m, host, T_A, C_IN)); 119 | } 120 | 121 | int 122 | mdns_lookup_PTR(struct mdns *m, const char *ptr) 123 | { 124 | return (mdns_lookup_do(m, ptr, T_PTR, C_IN)); 125 | } 126 | 127 | int 128 | mdns_lookup_rev(struct mdns *m, struct in_addr *addr) 129 | { 130 | char name[MAXHOSTNAMELEN]; 131 | 132 | reversstr(name, addr); 133 | name[sizeof(name) - 1] = '\0'; 134 | 135 | return (mdns_lookup_PTR(m, name)); 136 | } 137 | 138 | int 139 | mdns_lookup_HINFO(struct mdns *m, const char *host) 140 | { 141 | return (mdns_lookup_do(m, host, T_HINFO, C_IN)); 142 | } 143 | 144 | static int 145 | mdns_lookup_do(struct mdns *m, const char name[MAXHOSTNAMELEN], u_int16_t type, 146 | u_int16_t class) 147 | { 148 | struct rrset rrs; 149 | 150 | bzero(&rrs, sizeof(rrs)); 151 | rrs.type = type; 152 | rrs.class = class; 153 | if (strlcpy(rrs.dname, name, sizeof(rrs.dname)) >= sizeof(rrs.dname)) { 154 | errno = ENAMETOOLONG; 155 | return (-1); 156 | } 157 | if (ibuf_send_imsg(&m->ibuf, IMSG_CTL_LOOKUP, 158 | &rrs, sizeof(rrs)) == -1) 159 | return (-1); /* XXX: set errno */ 160 | 161 | return (0); 162 | } 163 | 164 | int 165 | mdns_browse_add(struct mdns *m, const char *app, const char *proto) 166 | { 167 | return (mdns_browse_adddel(m, app, proto, IMSG_CTL_BROWSE_ADD)); 168 | } 169 | 170 | int 171 | mdns_browse_del(struct mdns *m, const char *app, const char *proto) 172 | { 173 | return (mdns_browse_adddel(m, app, proto, IMSG_CTL_BROWSE_DEL)); 174 | } 175 | 176 | static int 177 | mdns_browse_adddel(struct mdns *m, const char *app, const char *proto, 178 | u_int msgtype) 179 | { 180 | struct rrset mlkup; 181 | 182 | if (app != NULL && strlen(app) > MAXHOSTNAMELEN) { 183 | errno = ENAMETOOLONG; 184 | return (-1); 185 | } 186 | 187 | bzero(&mlkup, sizeof(mlkup)); 188 | 189 | /* browsing for service types */ 190 | if (app == NULL && proto == NULL) 191 | (void)strlcpy(mlkup.dname, "_services._dns-sd._udp.local", 192 | sizeof(mlkup.dname)); 193 | else if (snprintf(mlkup.dname, sizeof(mlkup.dname), 194 | "_%s._%s.local", app, proto) >= (int) sizeof(mlkup.dname)) { 195 | errno = ENAMETOOLONG; 196 | return (-1); 197 | } 198 | mlkup.type = T_PTR; 199 | mlkup.class = C_IN; 200 | 201 | if (ibuf_send_imsg(&m->ibuf, msgtype, 202 | &mlkup, sizeof(mlkup)) == -1) 203 | return (-1); /* XXX: set errno */ 204 | 205 | return (0); 206 | } 207 | 208 | int 209 | mdns_resolve(struct mdns *m, const char *name, const char *app, 210 | const char *proto) 211 | { 212 | char buf[MAXHOSTNAMELEN]; 213 | 214 | if (strcmp(proto, "tcp") != 0 && strcmp(proto, "udp") != 0) { 215 | errno = EINVAL; 216 | return (-1); 217 | } 218 | 219 | if (snprintf(buf, sizeof(buf), "%s._%s._%s.local", 220 | name, app, proto) >= (int) sizeof(buf)) { 221 | errno = ENAMETOOLONG; 222 | return (-1); 223 | } 224 | 225 | buf[sizeof(buf) - 1] = '\0'; 226 | 227 | if (ibuf_send_imsg(&m->ibuf, IMSG_CTL_RESOLVE, 228 | buf, sizeof(buf)) == -1) 229 | return (-1); /* XXX: set errno */ 230 | 231 | return (0); 232 | } 233 | 234 | int 235 | mdns_group_add(struct mdns *m, const char *group) 236 | { 237 | char msg[MAXHOSTNAMELEN]; 238 | 239 | bzero(msg, sizeof(msg)); 240 | if (strlcpy(msg, group, sizeof(msg)) 241 | >= sizeof(msg)) 242 | return (-1); 243 | if (ibuf_send_imsg(&m->ibuf, IMSG_CTL_GROUP_ADD, 244 | msg, sizeof(msg)) == -1) 245 | return (-1); 246 | 247 | return (0); 248 | } 249 | 250 | int 251 | mdns_group_reset(struct mdns *m, const char *group) 252 | { 253 | char msg[MAXHOSTNAMELEN]; 254 | 255 | bzero(msg, sizeof(msg)); 256 | if (strlcpy(msg, group, sizeof(msg)) 257 | >= sizeof(msg)) 258 | return (-1); 259 | if (ibuf_send_imsg(&m->ibuf, IMSG_CTL_GROUP_RESET, 260 | msg, sizeof(msg)) == -1) 261 | return (-1); 262 | 263 | return (0); 264 | } 265 | 266 | int 267 | mdns_group_add_service(struct mdns *m, const char *group, 268 | struct mdns_service *ms) 269 | { 270 | if (strcmp(group, ms->name) != 0) 271 | return (-1); 272 | if (ibuf_send_imsg(&m->ibuf, IMSG_CTL_GROUP_ADD_SERVICE, 273 | ms, sizeof(*ms)) == -1) 274 | return (-1); 275 | 276 | return (0); 277 | } 278 | 279 | int 280 | mdns_group_commit(struct mdns *m, const char *group) 281 | { 282 | char msg[MAXHOSTNAMELEN]; 283 | 284 | if (strlcpy(msg, group, sizeof(msg)) 285 | >= sizeof(msg)) 286 | return (-1); 287 | if (ibuf_send_imsg(&m->ibuf, IMSG_CTL_GROUP_COMMIT, 288 | msg, sizeof(msg)) == -1) 289 | return (-1); 290 | 291 | return (0); 292 | } 293 | 294 | int 295 | mdns_service_init(struct mdns_service *ms, const char *name, const char *app, 296 | const char *proto, u_int16_t port, const char *txt, const char *target, 297 | struct in_addr *addr) 298 | { 299 | bzero(ms, sizeof(*ms)); 300 | 301 | if (strcmp(proto, "tcp") != 0 && strcmp(proto, "udp") != 0) 302 | return (-1); 303 | if (strlcpy(ms->name, name, sizeof(ms->name)) >= sizeof(ms->name)) 304 | return (-1); 305 | if (strlcpy(ms->app, app, sizeof(ms->app)) >= sizeof(ms->app)) 306 | return (-1); 307 | if (strlcpy(ms->proto, proto, sizeof(ms->proto)) >= sizeof(ms->proto)) 308 | return (-1); 309 | ms->port = port; 310 | if (strlcpy(ms->txt, txt, sizeof(ms->txt)) >= sizeof(ms->txt)) 311 | return (-1); 312 | if (target != NULL) 313 | if (strlcpy(ms->target, target, sizeof(ms->target)) >= sizeof(ms->target)) 314 | return (-1); 315 | if (addr != NULL) 316 | ms->addr = *addr; 317 | 318 | return (0); 319 | } 320 | 321 | ssize_t 322 | mdns_read(struct mdns *m) 323 | { 324 | int ev; 325 | size_t r; 326 | ssize_t n; 327 | struct imsg imsg; 328 | struct rr rr; 329 | struct mdns_service ms; 330 | char groupname[MAXHOSTNAMELEN]; 331 | 332 | n = imsg_read(&m->ibuf); 333 | 334 | if (n == -1 || n == 0) 335 | return (n); 336 | 337 | /* TODO call imsgctl_to_event() */ 338 | while ((r = imsg_get(&m->ibuf, &imsg)) > 0) { 339 | switch (imsg.hdr.type) { 340 | case IMSG_CTL_LOOKUP: /* FALLTHROUGH */ 341 | case IMSG_CTL_LOOKUP_FAILURE: 342 | if ((imsg.hdr.len - IMSG_HEADER_SIZE) != sizeof(rr)) 343 | return (-1); 344 | ev = imsg.hdr.type == IMSG_CTL_LOOKUP ? 345 | MDNS_LOOKUP_SUCCESS : MDNS_LOOKUP_FAILURE; 346 | memcpy(&rr, imsg.data, sizeof(rr)); 347 | r = mdns_handle_lookup(m, &rr, ev); 348 | break; 349 | case IMSG_CTL_BROWSE_ADD: 350 | case IMSG_CTL_BROWSE_DEL: 351 | if ((imsg.hdr.len - IMSG_HEADER_SIZE) != sizeof(rr)) 352 | return (-1); 353 | ev = imsg.hdr.type == IMSG_CTL_BROWSE_ADD ? 354 | MDNS_SERVICE_UP : MDNS_SERVICE_DOWN; 355 | memcpy(&rr, imsg.data, sizeof(rr)); 356 | r = mdns_handle_browse(m, &rr, ev); 357 | break; 358 | case IMSG_CTL_RESOLVE: 359 | case IMSG_CTL_RESOLVE_FAILURE: 360 | if ((imsg.hdr.len - IMSG_HEADER_SIZE) != sizeof(ms)) 361 | return (-1); 362 | ev = imsg.hdr.type == IMSG_CTL_RESOLVE ? 363 | MDNS_RESOLVE_SUCCESS : MDNS_RESOLVE_FAILURE; 364 | memcpy(&ms, imsg.data, sizeof(ms)); 365 | r = mdns_handle_resolve(m, &ms, ev); 366 | break; 367 | case IMSG_CTL_GROUP_ADD: 368 | case IMSG_CTL_GROUP_RESET: 369 | case IMSG_CTL_GROUP_ADD_SERVICE: 370 | case IMSG_CTL_GROUP_COMMIT: 371 | case IMSG_CTL_GROUP_ERR_COLLISION: 372 | case IMSG_CTL_GROUP_ERR_NOT_FOUND: 373 | case IMSG_CTL_GROUP_ERR_DOUBLE_ADD: 374 | case IMSG_CTL_GROUP_PROBING: 375 | case IMSG_CTL_GROUP_ANNOUNCING: 376 | case IMSG_CTL_GROUP_PUBLISHED: 377 | if ((imsg.hdr.len - IMSG_HEADER_SIZE) != 378 | sizeof(groupname)) 379 | return (-1); 380 | if ((ev = imsgctl_to_event(imsg.hdr.type)) == -1) 381 | return (-1); 382 | memcpy(groupname, imsg.data, sizeof(groupname)); 383 | r = mdns_handle_group(m, groupname, ev); 384 | break; 385 | default: 386 | /* TODO remove this once in the wild */ 387 | warnx("Unknown imsg type %d", imsg.hdr.type); 388 | return (-1); 389 | } 390 | 391 | imsg_free(&imsg); 392 | } 393 | 394 | return (n); 395 | } 396 | 397 | static int 398 | mdns_handle_lookup(struct mdns *m, struct rr *rr, int ev) 399 | { 400 | struct hinfo *h; 401 | switch (rr->rrs.type) { 402 | case T_A: 403 | if (m->lhk_A == NULL) 404 | return (0); 405 | m->lhk_A(m, ev, rr->rrs.dname, rr->rdata.A); 406 | break; 407 | case T_PTR: 408 | if (m->lhk_PTR == NULL) 409 | return (0); 410 | m->lhk_PTR(m, ev, rr->rrs.dname, rr->rdata.PTR); 411 | break; 412 | case T_HINFO: 413 | if (m->lhk_HINFO == NULL) 414 | return (0); 415 | h = &rr->rdata.HINFO; 416 | m->lhk_HINFO(m, ev, rr->rrs.dname, h->cpu, h->os); 417 | break; 418 | default: 419 | return (-1); 420 | } 421 | 422 | return (0); 423 | } 424 | 425 | static int 426 | mdns_handle_browse(struct mdns *m, struct rr *rr, int ev) 427 | { 428 | char name[MAXHOSTNAMELEN]; 429 | char app[MAXLABELLEN]; 430 | char proto[MAXPROTOLEN]; 431 | int hasname; 432 | 433 | if (rr->rrs.type != T_PTR) 434 | return (-1); 435 | 436 | if (m->bhk == NULL) 437 | return (0); 438 | 439 | if (splitdname(rr->rdata.PTR, name, app, proto, &hasname) == -1) 440 | return (-1); 441 | 442 | if (hasname) 443 | m->bhk(m, ev, name, app, proto); 444 | else 445 | m->bhk(m, ev, NULL, app, proto); 446 | 447 | return (0); 448 | } 449 | 450 | static int 451 | mdns_handle_resolve(struct mdns *m, struct mdns_service *ms, int ev) 452 | { 453 | int hasname; 454 | 455 | if (m->rhk == NULL) 456 | return (0); 457 | if (splitdname(ms->name, ms->name, ms->app, ms->proto, &hasname) == -1) 458 | return (-1); 459 | if (hasname == 0) 460 | return (-1); 461 | 462 | m->rhk(m, ev, ms); 463 | 464 | return (0); 465 | } 466 | 467 | static int 468 | mdns_handle_group(struct mdns *m, char groupname[MAXHOSTNAMELEN], int ev) 469 | { 470 | if (m->ghk == NULL) 471 | return (0); 472 | 473 | m->ghk(m, ev, groupname); 474 | 475 | return (0); 476 | } 477 | 478 | static int 479 | mdns_connect(void) 480 | { 481 | struct sockaddr_un sun; 482 | int sockfd; 483 | 484 | bzero(&sun, sizeof(sun)); 485 | if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 486 | return (-1); 487 | sun.sun_family = AF_UNIX; 488 | (void)strlcpy(sun.sun_path, MDNSD_SOCKET, 489 | sizeof(sun.sun_path)); 490 | if (connect(sockfd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 491 | if (errno == ENOENT) 492 | errno = ECONNREFUSED; 493 | close(sockfd); 494 | return (-1); 495 | } 496 | 497 | return (sockfd); 498 | } 499 | 500 | static int 501 | ibuf_send_imsg(struct imsgbuf *ibuf, u_int32_t type, 502 | void *data, u_int16_t datalen) 503 | { 504 | struct ibuf *wbuf; 505 | 506 | if ((wbuf = imsg_create(ibuf, type, 0, 507 | 0, datalen)) == NULL) 508 | return (-1); 509 | 510 | if (imsg_add(wbuf, data, datalen) == -1) 511 | return (-1); 512 | 513 | wbuf->fd = -1; 514 | 515 | imsg_close(ibuf, wbuf); 516 | 517 | if (msgbuf_write(&ibuf->w) == -1) 518 | return (-1); 519 | 520 | return (0); 521 | } 522 | 523 | /* XXX: Too ugly, code me again with love */ 524 | static int 525 | splitdname(char fname[MAXHOSTNAMELEN], char sname[MAXHOSTNAMELEN], 526 | char app[MAXLABEL], char proto[MAXPROTOLEN], int *hasname) 527 | { 528 | char namecp[MAXHOSTNAMELEN]; 529 | char *p, *start; 530 | 531 | *hasname = 1; 532 | /* ubuntu810desktop [00:0c:29:4d:22:ce]._workstation._tcp.local */ 533 | /* _workstation._tcp.local */ 534 | /* work on a copy */ 535 | (void)strlcpy(namecp, fname, sizeof(namecp)); 536 | 537 | /* check if we have a name, or only an application protocol */ 538 | if ((p = strstr(namecp, "._")) != NULL) { 539 | p += 2; 540 | if ((p = strstr(p, "._")) == NULL) 541 | *hasname = 0; 542 | } 543 | 544 | start = namecp; 545 | 546 | /* if we have a name, copy */ 547 | if (*hasname == 1 && sname != NULL) { 548 | if ((p = strstr(start, "._")) == NULL) 549 | return (-1); 550 | *p++ = 0; 551 | p++; 552 | (void)strlcpy(sname, start, MAXHOSTNAMELEN); 553 | start = p; 554 | } 555 | else 556 | start++; 557 | 558 | if ((p = strstr(start, "._")) == NULL) 559 | return (-1); 560 | *p++ = 0; 561 | p++; 562 | (void)strlcpy(app, start, MAXLABEL); 563 | start = p; 564 | 565 | if ((p = strstr(start, ".")) == NULL) 566 | return (-1); 567 | *p++ = 0; 568 | (void)strlcpy(proto, start, MAXPROTOLEN); 569 | 570 | return (0); 571 | } 572 | 573 | static int 574 | imsgctl_to_event(int msgtype) 575 | { 576 | switch (msgtype) { 577 | case IMSG_CTL_GROUP_ERR_COLLISION: 578 | return 579 | (MDNS_GROUP_ERR_COLLISION); 580 | break; 581 | case IMSG_CTL_GROUP_ERR_NOT_FOUND: 582 | return 583 | (MDNS_GROUP_ERR_NOT_FOUND); 584 | break; 585 | case IMSG_CTL_GROUP_ERR_DOUBLE_ADD: 586 | return 587 | (MDNS_GROUP_ERR_DOUBLE_ADD); 588 | break; 589 | case IMSG_CTL_GROUP_PROBING: 590 | return 591 | (MDNS_GROUP_PROBING); 592 | break; 593 | case IMSG_CTL_GROUP_ANNOUNCING: 594 | return 595 | (MDNS_GROUP_ANNOUNCING); 596 | break; 597 | case IMSG_CTL_GROUP_PUBLISHED: 598 | return 599 | (MDNS_GROUP_PUBLISHED); 600 | break; 601 | default: 602 | /* TODO remove this once in the wild */ 603 | warnx("imsgctl_to_event: Unknown imsgctl %d", 604 | msgtype); 605 | } 606 | /* NOTREACHED */ 607 | return (-1); 608 | } 609 | 610 | void 611 | reversstr(char str[MAXHOSTNAMELEN], struct in_addr *addr) 612 | { 613 | const u_char *uaddr = (const u_char *)addr; 614 | 615 | (void) snprintf(str, MAXHOSTNAMELEN, "%u.%u.%u.%u.in-addr.arpa", 616 | (uaddr[3] & 0xff), (uaddr[2] & 0xff), 617 | (uaddr[1] & 0xff), (uaddr[0] & 0xff)); 618 | } 619 | 620 | -------------------------------------------------------------------------------- /libmdns/shlib_version: -------------------------------------------------------------------------------- 1 | major=0 2 | minor=1 3 | -------------------------------------------------------------------------------- /mdnsctl/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX?=/usr/local 2 | BINDIR=${PREFIX}/bin 3 | MANDIR= ${PREFIX}/man/cat 4 | 5 | PROG= mdnsctl 6 | SRCS= mdnsctl.c parser.c 7 | 8 | CFLAGS+= -g -Wall 9 | CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes 10 | CFLAGS+= -Wmissing-declarations 11 | CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual 12 | CFLAGS+= -Wsign-compare 13 | CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../mdnsd 14 | 15 | .if exists(${.CURDIR}/../libmdns/${__objdir}) 16 | LDADD+= -L${.CURDIR}/../libmdns/${__objdir} -lmdns 17 | .else 18 | LDADD+= -L${.CURDIR}/../libmdns -lmdns 19 | .endif 20 | LDADD+= -lutil 21 | DPADD+= ${LIBUTIL} 22 | 23 | MAN= mdnsctl.8 24 | 25 | .include 26 | -------------------------------------------------------------------------------- /mdnsctl/mdnsctl.8: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2010, 2011, Christiano F. Haesbaert 3 | .\" 4 | .\" Permission to use, copy, modify, and distribute this software for any 5 | .\" purpose with or without fee is hereby granted, provided that the above 6 | .\" copyright notice and this permission notice appear in all copies. 7 | .\" 8 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | .\" 16 | .Dd $Mdocdate: Apr 19 2016 $ 17 | .Dt MDNSCTL 8 18 | .Os 19 | .Sh NAME 20 | .Nm mdnsctl 21 | .Nd control the Multicast DNS server daemon 22 | .Sh SYNOPSIS 23 | .Nm 24 | .Ar command 25 | .Op Ar argument ... 26 | .Sh DESCRIPTION 27 | The 28 | .Nm 29 | program controls the 30 | .Xr mdnsd 8 31 | daemon, it can perform simples mDNS lookups, as well as browsing and publishing 32 | mDNS/DNS-SD services. 33 | .Pp 34 | The following commands are available: 35 | .Bl -tag -width xxxxxx 36 | .It Xo 37 | .Cm lookup 38 | .Op Ar rr-types 39 | .Ar host.local 40 | .Xc 41 | Look up resource records for 42 | .Ar host.local . 43 | The optional 44 | .Ar rr-types 45 | specifies which type of resource record should be looked up. 46 | It can be any combination of the following: 47 | .Pp 48 | .Bl -tag -width " " -compact 49 | .It Cm -a 50 | A record (IPv4 Address). This is the default. 51 | .It Cm -h 52 | HINFO record (Host Information). 53 | .It Cm -s 54 | SRV record (Service). Unimplemented. 55 | .It Cm -t 56 | TXT record (Text). Unimplemented. 57 | .El 58 | .It Cm rlookup Ar a.b.c.d 59 | Reverse lookup an IPv4 address in the 60 | .Ar a.b.c.d 61 | form, use this to obtain the hostname of the given 62 | address. 63 | .It Xo 64 | .Cm browse 65 | .Op Fl r 66 | .Op Fl s 67 | .Op Ar application proto 68 | .Xc 69 | Browse for application services of type 70 | .Ar application 71 | for the given transport protocol 72 | .Ar proto . 73 | .Ar application 74 | may be any application service type, like http, workstation, ftp, printer... 75 | .Ar proto 76 | must be either tcp or udp. 77 | Defaults to all services if none specified. 78 | .It Xo 79 | .Cm publish 80 | .Ar service-name 81 | .Ar application 82 | .Ar proto 83 | .Ar port 84 | .Ar text-string 85 | .Xc 86 | Publish services via dns-sd, 87 | .Ar service-name 88 | is the unique chosen name for the service, it can be any string up to 63 89 | characters. 90 | The 91 | .Ar application 92 | is the application protocol for the service, like http, ftp... 93 | .Ar proto 94 | is the transport protocol, must be either tcp or udp. 95 | .Ar port 96 | is the tcp or udp port. 97 | .Ar text-string 98 | is the string in the TXT record for the given service, it can be used to 99 | express additional service information. 100 | .It Xo 101 | .Cm proxy 102 | .Ar service-name 103 | .Ar application 104 | .Ar proto 105 | .Ar port 106 | .Ar host 107 | .Ar address 108 | .Ar text-string 109 | .Xc 110 | Proxy publish a service running on a different machine, 111 | in addition to the arguments used for 112 | .Sx \&publish , 113 | .Ar host 114 | is a fully qualified domain name (FQDN) of the target machine, 115 | .Ar address 116 | is an IPv4 address for the target machine in the 117 | .Ar a.b.c.d 118 | form. 119 | .El 120 | .Sh FILES 121 | .Bl -tag -width "/var/run/mdnsctl.sockXX" -compact 122 | .It Pa /var/run/mdnsctl.sock 123 | .Ux Ns -domain 124 | socket used for communication with 125 | .Xr mdnsd 8 . 126 | .El 127 | .Sh EXAMPLES 128 | The following examples demonstrate some basic uses of 129 | .Nm . 130 | .Pp 131 | Lookup a host A and HINFO record 132 | .Pp 133 | .Dl # mdnsctl lookup -ah foobar.local 134 | .Pp 135 | Reverse lookup an address 136 | .Pp 137 | .Dl # mdnsctl rlookup 192.168.8.32 138 | .Pp 139 | Browse up all services in the local network 140 | .Pp 141 | .Dl # mdnsctl browse 142 | .Pp 143 | Browse and resolve all services 144 | .Pp 145 | .Dl # mdnsctl browse -r 146 | .Pp 147 | Browse and resolve all services and output in script-readable format 148 | .Pp 149 | .Dl # mdnsctl browse -rs 150 | .Pp 151 | Browse and resolve all the http services in the local network 152 | .Pp 153 | .Dl # mdnsctl browse -r http tcp 154 | .Pp 155 | Publish a simple ftp service 156 | .Pp 157 | .Dl # mdnsctl publish myftp ftp tcp 21 "user=foobar" 158 | .Pp 159 | Proxy publish a https service that has www.mysite.com as the target 160 | .Pp 161 | .Dl # mdnsctl proxy mysite https tcp 443 www.mysite.com 12.3.45.6 "user=foobar" 162 | .Sh SEE ALSO 163 | .Xr mdnsd 8 164 | .Sh LICENSE 165 | .Nm 166 | is released under the ISC license. 167 | .Sh HISTORY 168 | The 169 | .Nm 170 | program version 0.1 was released in 13 February 2011. 171 | .Sh AUTHORS 172 | .An Christiano Farina Haesbaert Aq Mt haesbaert@haesbaert.org 173 | -------------------------------------------------------------------------------- /mdnsctl/mdnsctl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010,2011 Christiano F. Haesbaert 3 | * Copyright (c) 2006 Michele Marchetto 4 | * Copyright (c) 2005 Claudio Jeker 5 | * Copyright (c) 2004, 2005 Esben Norby 6 | * Copyright (c) 2003 Henning Brauer 7 | * 8 | * Permission to use, copy, modify, and distribute this software for any 9 | * purpose with or without fee is hereby granted, provided that the above 10 | * copyright notice and this permission notice appear in all copies. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include "mdns.h" 39 | #include "parser.h" 40 | 41 | __dead void usage(void); 42 | void my_lookup_A_hook(struct mdns *, int, const char *, struct in_addr); 43 | void my_lookup_PTR_hook(struct mdns *, int, const char *, const char *); 44 | void my_lookup_HINFO_hook(struct mdns *, int, const char *, 45 | const char *, const char *); 46 | void my_browse_hook(struct mdns *, int, const char *, const char *, 47 | const char *); 48 | void my_resolve_hook(struct mdns *, int, struct mdns_service *); 49 | void my_group_hook(struct mdns *, int, const char *); 50 | 51 | 52 | struct parse_result *res; 53 | 54 | __dead void 55 | usage(void) 56 | { 57 | extern char *__progname; 58 | 59 | fprintf(stderr, "usage: %s command [argument ...]\n", __progname); 60 | exit(1); 61 | } 62 | 63 | int 64 | main(int argc, char *argv[]) 65 | { 66 | int sockfd; 67 | struct mdns mdns; 68 | struct mdns_service ms; 69 | 70 | if (pledge("stdio unix", NULL) == -1) 71 | err(1, NULL); 72 | 73 | /* parse options */ 74 | if ((res = parse(argc - 1, argv + 1)) == NULL) 75 | exit(1); 76 | 77 | if ((sockfd = mdns_open(&mdns)) == -1) 78 | err(1, "mdns_open"); 79 | 80 | if (pledge("stdio", NULL) == -1) 81 | err(1, NULL); 82 | 83 | mdns_set_lookup_A_hook(&mdns, my_lookup_A_hook); 84 | mdns_set_lookup_PTR_hook(&mdns, my_lookup_PTR_hook); 85 | mdns_set_lookup_HINFO_hook(&mdns, my_lookup_HINFO_hook); 86 | mdns_set_browse_hook(&mdns, my_browse_hook); 87 | mdns_set_resolve_hook(&mdns, my_resolve_hook); 88 | mdns_set_group_hook(&mdns, my_group_hook); 89 | 90 | /* process user request */ 91 | switch (res->action) { 92 | case NONE: 93 | usage(); 94 | /* not reached */ 95 | break; 96 | case LOOKUP: 97 | if (res->flags & F_A || res->flags == 0) 98 | if (mdns_lookup_A(&mdns, res->hostname) == -1) 99 | err(1, "mdns_lookup_A"); 100 | 101 | if (res->flags & F_HINFO) 102 | if (mdns_lookup_HINFO(&mdns, res->hostname) == -1) 103 | err(1, "mdns_lookup_A"); 104 | 105 | if (res->flags & F_PTR) 106 | if (mdns_lookup_PTR(&mdns, res->hostname) == -1) 107 | err(1, "mdns_lookup_A"); 108 | break; 109 | case RLOOKUP: 110 | if (mdns_lookup_rev(&mdns, &res->addr) == -1) 111 | err(1, "mdns_lookup_A"); 112 | break; 113 | case BROWSE_PROTO: 114 | if (mdns_browse_add(&mdns, res->app, res->proto) == -1) 115 | err(1, "mdns_browse_add"); 116 | break; /* NOTREACHED */ 117 | case PUBLISH: 118 | if (mdns_group_add(&mdns, res->srvname) == -1) 119 | err(1, "mdns_group_add"); 120 | if (mdns_service_init(&ms, res->srvname, res->app, res->proto, 121 | res->port, res->txtstring, NULL, NULL) == -1) 122 | errx(1, "mdns_service_init"); 123 | if (mdns_group_add_service(&mdns, res->srvname, &ms) == -1) 124 | errx(1, "mdns_group_add_service"); 125 | if (mdns_group_commit(&mdns, res->srvname) == -1) 126 | errx(1, "mdns_group_commit"); 127 | break; 128 | case PROXY: 129 | if (mdns_group_add(&mdns, res->srvname) == -1) 130 | err(1, "mdns_group_add"); 131 | if (mdns_service_init(&ms, res->srvname, res->app, res->proto, 132 | res->port, res->txtstring, res->hostname, &res->addr) == -1) 133 | errx(1, "mdns_service_init"); 134 | if (mdns_group_add_service(&mdns, res->srvname, &ms) == -1) 135 | errx(1, "mdns_group_add_service"); 136 | if (mdns_group_commit(&mdns, res->srvname) == -1) 137 | errx(1, "mdns_group_commit"); 138 | break; 139 | default: 140 | errx(1, "Unknown action"); 141 | break; /* NOTREACHED */ 142 | } 143 | 144 | for (; ;) { 145 | ssize_t n; 146 | 147 | n = mdns_read(&mdns); 148 | fflush(stdout); 149 | if (n == -1) 150 | err(1, "mdns_read"); 151 | if (n == 0) 152 | errx(1, "Server closed socket"); 153 | if ((res->action == LOOKUP || 154 | res->action == RLOOKUP) 155 | && res->flags == 0) 156 | exit(0); 157 | } 158 | } 159 | 160 | void 161 | my_lookup_A_hook(struct mdns *m, int ev, const char *host, struct in_addr a) 162 | { 163 | switch (ev) { 164 | case MDNS_LOOKUP_SUCCESS: 165 | printf("Address: %s\n", inet_ntoa(a)); 166 | break; 167 | case MDNS_LOOKUP_FAILURE: 168 | printf("Address not found\n"); 169 | break; 170 | default: 171 | errx(1, "Unhandled event"); 172 | break; /* NOTREACHED */ 173 | } 174 | 175 | res->flags &= ~F_A; 176 | } 177 | 178 | void 179 | my_lookup_PTR_hook(struct mdns *m, int ev, const char *name, const char *ptr) 180 | { 181 | switch (ev) { 182 | case MDNS_LOOKUP_SUCCESS: 183 | printf("Hostname: %s\n", ptr); 184 | break; 185 | case MDNS_LOOKUP_FAILURE: 186 | printf("Hostname not found\n"); 187 | break; 188 | default: 189 | errx(1, "Unhandled event"); 190 | break; /* NOTREACHED */ 191 | } 192 | 193 | res->flags &= ~F_PTR; 194 | } 195 | 196 | void 197 | my_lookup_HINFO_hook(struct mdns *m, int ev, const char *name, const char *cpu, 198 | const char *os) 199 | { 200 | switch (ev) { 201 | case MDNS_LOOKUP_SUCCESS: 202 | printf("Cpu: %s\n", cpu); 203 | printf("Os: %s\n", os); 204 | break; 205 | case MDNS_LOOKUP_FAILURE: 206 | printf("HINFO not found\n"); 207 | break; 208 | default: 209 | errx(1, "Unhandled event"); 210 | break; /* NOTREACHED */ 211 | } 212 | 213 | res->flags &= ~F_HINFO; 214 | } 215 | 216 | void 217 | my_browse_hook(struct mdns *m, int ev, const char *name, const char *app, 218 | const char *proto) 219 | { 220 | switch (ev) { 221 | case MDNS_SERVICE_UP: 222 | /* If no name, this is a service type */ 223 | if (name == NULL) { 224 | if (mdns_browse_add(m, app, proto) == -1) 225 | err(1, "mdns_browse_add"); 226 | return; 227 | } 228 | if (res->flags & F_RESOLV) { 229 | if (mdns_resolve(m, name, app, proto) == -1) 230 | err(1, "mdns_resolve"); 231 | return; 232 | } 233 | if (res->flags & F_SCRIPT) 234 | printf("up|proto|%s|app|%s|name|%s\n", proto, app, name); 235 | else 236 | printf("+++ %-48s %-20s %-3s\n", name, app, proto); 237 | break; 238 | case MDNS_SERVICE_DOWN: 239 | if (name != NULL) { 240 | if (res->flags & F_SCRIPT) 241 | printf("down|proto|%s|app|%s|name|%s\n", proto, app, name); 242 | else 243 | printf("--- %-48s %-20s %-3s\n", name, app, proto); 244 | } 245 | break; 246 | default: 247 | errx(1, "Unhandled event"); 248 | break; 249 | } 250 | } 251 | 252 | void 253 | my_resolve_hook(struct mdns *m, int ev, struct mdns_service *ms) 254 | { 255 | switch (ev) { 256 | case MDNS_RESOLVE_FAILURE: 257 | fprintf(stderr, "Can't resolve %s", ms->name); 258 | fflush(stderr); 259 | break; /* NOTREACHED */ 260 | case MDNS_RESOLVE_SUCCESS: 261 | if (res->flags & F_SCRIPT) { 262 | printf("up|proto|%s|app|%s|name|%s|port|%u|target|%s|address|%s|txt|%s\n", 263 | ms->proto, ms->app, ms->name, ms->port, ms->target, 264 | inet_ntoa(ms->addr), ms->txt); 265 | } else { 266 | printf("+++ %-48s %-20s %-3s\n", ms->name, ms->app, ms->proto); 267 | printf(" Name: %s\n", ms->name); 268 | /* printf(" Priority: %u\n", ms->priority); */ 269 | /* printf(" Weight: %u\n", ms->weight); */ 270 | printf(" Port: %u\n", ms->port); 271 | printf(" Target: %s\n", ms->target); 272 | printf(" Address: %s\n", inet_ntoa(ms->addr)); 273 | printf(" Txt: %s\n", ms->txt); 274 | } 275 | break; 276 | default: 277 | errx(1, "Unhandled event"); 278 | break; 279 | } 280 | } 281 | 282 | void 283 | my_group_hook(struct mdns *m, int ev, const char *group) 284 | { 285 | switch (ev) { 286 | case MDNS_GROUP_ERR_COLLISION: 287 | printf("Group %s got a collision, not published\n", 288 | group); 289 | exit(1); 290 | break; 291 | case MDNS_GROUP_ERR_NOT_FOUND: 292 | printf("Group %s not found, this is an internal error," 293 | " please report\n", group); 294 | exit(1); 295 | break; 296 | case MDNS_GROUP_ERR_DOUBLE_ADD: 297 | printf("Group %s got a double add, ignore for now...\n", 298 | group); 299 | exit(1); 300 | break; 301 | case MDNS_GROUP_PROBING: 302 | printf("Group %s is probing...\n", group); 303 | break; 304 | case MDNS_GROUP_ANNOUNCING: 305 | printf("Group %s is announcing...\n", group); 306 | break; 307 | case MDNS_GROUP_PUBLISHED: 308 | printf("Group %s published.\n", group); 309 | break; 310 | default: 311 | warnx("Unhandle group event"); 312 | break; 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /mdnsctl/parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Christiano F. Haesbaert 3 | * Copyright (c) 2006 Michele Marchetto 4 | * Copyright (c) 2004 Esben Norby 5 | * Copyright (c) 2003, 2004 Henning Brauer 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "parser.h" 34 | 35 | enum token_type { 36 | NOTOKEN, 37 | ENDTOKEN, 38 | KEYWORD, 39 | ADDRESS, 40 | FLAGS, 41 | HOSTNAME, 42 | FQDN, 43 | PROTO, 44 | APPPROTO, 45 | BRFLAGS, 46 | SRVNAME, 47 | TXTSTRING, 48 | PORT 49 | }; 50 | 51 | struct token { 52 | enum token_type type; 53 | const char *keyword; 54 | int value; 55 | const struct token *next; 56 | }; 57 | 58 | static const struct token t_main[]; 59 | static const struct token t_lookup[]; 60 | static const struct token t_rlookup[]; 61 | static const struct token t_browse_proto[]; 62 | static const struct token t_browse_app[]; 63 | static const struct token t_publish[]; 64 | static const struct token t_publish_app[]; 65 | static const struct token t_publish_app_proto[]; 66 | static const struct token t_publish_app_proto_port[]; 67 | static const struct token t_publish_app_proto_port_txt[]; 68 | static const struct token t_proxy[]; 69 | static const struct token t_proxy_app[]; 70 | static const struct token t_proxy_app_proto[]; 71 | static const struct token t_proxy_app_proto_port[]; 72 | static const struct token t_proxy_app_proto_port_target[]; 73 | static const struct token t_proxy_app_proto_port_target_addr[]; 74 | static const struct token t_proxy_app_proto_port_target_addr_txt[]; 75 | 76 | static const struct token t_main[] = { 77 | {KEYWORD, "lookup", NONE, t_lookup}, 78 | {KEYWORD, "rlookup", NONE, t_rlookup}, 79 | {KEYWORD, "browse", BROWSE_PROTO, t_browse_app}, 80 | {KEYWORD, "publish", NONE, t_publish}, 81 | {KEYWORD, "proxy", NONE, t_proxy}, 82 | {ENDTOKEN, "", NONE, NULL} 83 | }; 84 | 85 | static const struct token t_lookup[] = { 86 | { FLAGS , "-", NONE, t_lookup}, 87 | { HOSTNAME, "", LOOKUP, NULL}, 88 | { ENDTOKEN, "", NONE, NULL} 89 | }; 90 | 91 | static const struct token t_rlookup[] = { 92 | { ADDRESS, "", RLOOKUP, NULL}, 93 | { ENDTOKEN, "", NONE, NULL} 94 | }; 95 | 96 | static const struct token t_browse_app[] = { 97 | { BRFLAGS, "-", NONE, t_browse_app}, 98 | { APPPROTO, "", NONE, t_browse_proto}, 99 | { NOTOKEN, "", BROWSE_PROTO, NULL}, 100 | { ENDTOKEN, "", NONE, NULL} 101 | }; 102 | 103 | static const struct token t_browse_proto[] = { 104 | { PROTO, "tcp", BROWSE_PROTO, NULL}, 105 | { PROTO, "udp", BROWSE_PROTO, NULL}, 106 | { ENDTOKEN, "", NONE, NULL} 107 | }; 108 | 109 | static const struct token t_publish[] = { 110 | { SRVNAME, "", NONE, t_publish_app}, 111 | { ENDTOKEN, "", NONE, NULL} 112 | }; 113 | 114 | static const struct token t_publish_app[] = { 115 | { APPPROTO, "", NONE, t_publish_app_proto}, 116 | { ENDTOKEN, "", NONE, NULL} 117 | }; 118 | 119 | static const struct token t_publish_app_proto[] = { 120 | { PROTO, "tcp", NONE, t_publish_app_proto_port}, 121 | { PROTO, "udp", NONE, t_publish_app_proto_port}, 122 | { ENDTOKEN, "", NONE, NULL} 123 | }; 124 | 125 | static const struct token t_publish_app_proto_port[] = { 126 | { PORT, "", NONE, t_publish_app_proto_port_txt}, 127 | { ENDTOKEN, "", NONE, t_publish_app_proto_port_txt} 128 | }; 129 | 130 | static const struct token t_publish_app_proto_port_txt[] = { 131 | { TXTSTRING, "", PUBLISH, NULL}, 132 | { ENDTOKEN, "", NONE, NULL} 133 | }; 134 | static const struct token t_proxy[] = { 135 | { SRVNAME, "", NONE, t_proxy_app}, 136 | { ENDTOKEN, "", NONE, NULL} 137 | }; 138 | 139 | static const struct token t_proxy_app[] = { 140 | { APPPROTO, "", NONE, t_proxy_app_proto}, 141 | { ENDTOKEN, "", NONE, NULL} 142 | }; 143 | 144 | static const struct token t_proxy_app_proto[] = { 145 | { PROTO, "tcp", NONE, t_proxy_app_proto_port}, 146 | { PROTO, "udp", NONE, t_proxy_app_proto_port}, 147 | { ENDTOKEN, "", NONE, NULL} 148 | }; 149 | 150 | static const struct token t_proxy_app_proto_port[] = { 151 | { PORT, "", NONE, t_proxy_app_proto_port_target}, 152 | { ENDTOKEN, "", NONE, t_proxy_app_proto_port_target} 153 | }; 154 | 155 | static const struct token t_proxy_app_proto_port_target[] = { 156 | { FQDN, "", NONE, t_proxy_app_proto_port_target_addr}, 157 | { ENDTOKEN, "", NONE, t_proxy_app_proto_port_target_addr} 158 | }; 159 | 160 | static const struct token t_proxy_app_proto_port_target_addr[] = { 161 | { ADDRESS, "", NONE, t_proxy_app_proto_port_target_addr_txt}, 162 | { ENDTOKEN, "", NONE, t_proxy_app_proto_port_target_addr_txt} 163 | }; 164 | 165 | static const struct token t_proxy_app_proto_port_target_addr_txt[] = { 166 | { TXTSTRING, "", PROXY, NULL}, 167 | { ENDTOKEN, "", NONE, NULL} 168 | }; 169 | 170 | static struct parse_result res; 171 | 172 | struct parse_result * 173 | parse(int argc, char *argv[]) 174 | { 175 | const struct token *table = t_main; 176 | const struct token *match; 177 | 178 | bzero(&res, sizeof(res)); 179 | 180 | while (argc >= 0) { 181 | if ((match = match_token(argv[0], table)) == NULL) { 182 | fprintf(stderr, "valid commands/args:\n"); 183 | show_valid_args(table); 184 | return (NULL); 185 | } 186 | 187 | argc--; 188 | argv++; 189 | 190 | if (match->type == NOTOKEN || match->next == NULL) 191 | break; 192 | 193 | table = match->next; 194 | } 195 | 196 | if (argc > 0) { 197 | fprintf(stderr, "superfluous argument: %s\n", argv[0]); 198 | return (NULL); 199 | } 200 | 201 | return (&res); 202 | } 203 | 204 | const struct token * 205 | match_token(const char *word, const struct token *table) 206 | { 207 | u_int i, match; 208 | const char *errstr; 209 | const struct token *t = NULL; 210 | 211 | match = 0; 212 | 213 | for (i = 0; table[i].type != ENDTOKEN; i++) { 214 | switch (table[i].type) { 215 | case NOTOKEN: 216 | if (word == NULL || strlen(word) == 0) { 217 | match++; 218 | t = &table[i]; 219 | } 220 | break; 221 | case BRFLAGS: 222 | if (parse_brflags(word, &res.flags)) { 223 | match++; 224 | t = &table[i]; 225 | if (t->value) 226 | res.action = t->value; 227 | } 228 | break; 229 | case FLAGS: 230 | if (parse_flags(word, &res.flags)) { 231 | match++; 232 | t = &table[i]; 233 | if (t->value) 234 | res.action = t->value; 235 | } 236 | break; 237 | case KEYWORD: 238 | if (word != NULL && strcmp(word, table[i].keyword) 239 | == 0) { 240 | match++; 241 | t = &table[i]; 242 | if (t->value) 243 | res.action = t->value; 244 | } 245 | break; 246 | case PROTO: 247 | if (word != NULL && strcmp(word, table[i].keyword) 248 | == 0) { 249 | res.proto = word; 250 | match++; 251 | t = &table[i]; 252 | if (t->value) 253 | res.action = t->value; 254 | } 255 | break; 256 | case ADDRESS: 257 | if (parse_addr(word, &res.addr)) { 258 | match++; 259 | t = &table[i]; 260 | if (t->value) 261 | res.action = t->value; 262 | } 263 | break; 264 | case HOSTNAME: 265 | if (parse_hostname(word, res.hostname)) { 266 | match++; 267 | t = &table[i]; 268 | if (t->value) 269 | res.action = t->value; 270 | } 271 | break; 272 | case FQDN: 273 | if (parse_target_hostname(word, res.hostname)) { 274 | match++; 275 | t = &table[i]; 276 | if (t->value) 277 | res.action = t->value; 278 | } 279 | break; 280 | case APPPROTO: 281 | if (word != NULL && *word != '-') { 282 | res.app = word; 283 | match++; 284 | t = &table[i]; 285 | if (t->value) 286 | res.action = t->value; 287 | } 288 | break; 289 | case SRVNAME: /* match anything */ 290 | if (word != NULL) { 291 | res.srvname = word; 292 | match++; 293 | t = &table[i]; 294 | if (t->value) 295 | res.action = t->value; 296 | } 297 | break; 298 | case TXTSTRING: 299 | if (word != NULL) { 300 | res.txtstring = word; 301 | match++; 302 | t = &table[i]; 303 | if (t->value) 304 | res.action = t->value; 305 | } 306 | break; 307 | case PORT: 308 | if (word != NULL) { 309 | res.port = strtonum(word, 0, UINT16_MAX, 310 | &errstr); 311 | if (errstr) 312 | errx(1, "strtonum: %s", errstr); 313 | match++; 314 | t = &table[i]; 315 | if (t->value) 316 | res.action = t->value; 317 | } 318 | break; 319 | case ENDTOKEN: 320 | break; 321 | } 322 | } 323 | 324 | if (match != 1) { 325 | if (word == NULL) 326 | fprintf(stderr, "missing argument:\n"); 327 | else if (match > 1) 328 | fprintf(stderr, "ambiguous argument: %s\n", word); 329 | else if (match < 1) 330 | fprintf(stderr, "unknown argument: %s\n", word); 331 | return (NULL); 332 | } 333 | 334 | return (t); 335 | } 336 | 337 | void 338 | show_valid_args(const struct token *table) 339 | { 340 | int i; 341 | 342 | for (i = 0; table[i].type != ENDTOKEN; i++) { 343 | switch (table[i].type) { 344 | case NOTOKEN: 345 | fprintf(stderr, " \n"); 346 | break; 347 | case KEYWORD: 348 | fprintf(stderr, " %s\n", table[i].keyword); 349 | break; 350 | case PROTO: 351 | fprintf(stderr, " %s\n", table[i].keyword); 352 | break; 353 | case ADDRESS: 354 | fprintf(stderr, "
\n"); 355 | break; 356 | case HOSTNAME: 357 | fprintf(stderr, " \n"); 358 | break; 359 | case FQDN: 360 | fprintf(stderr, " \n"); 361 | break; 362 | case APPPROTO: 363 | fprintf(stderr, " \n"); 364 | break; 365 | case FLAGS: 366 | fprintf(stderr, " <-ahst>\n"); 367 | break; 368 | case BRFLAGS: 369 | fprintf(stderr, " <-r>\n"); 370 | break; 371 | case SRVNAME: 372 | fprintf(stderr, " \n"); 373 | break; 374 | case TXTSTRING: 375 | fprintf(stderr, " \n"); 376 | break; 377 | case PORT: 378 | fprintf(stderr, " \n"); 379 | break; 380 | case ENDTOKEN: 381 | break; 382 | } 383 | } 384 | } 385 | 386 | int 387 | parse_addr(const char *word, struct in_addr *addr) 388 | { 389 | struct in_addr ina; 390 | 391 | if (word == NULL || !isdigit(*word)) 392 | return (0); 393 | 394 | bzero(addr, sizeof(struct in_addr)); 395 | bzero(&ina, sizeof(ina)); 396 | if (inet_pton(AF_INET, word, &ina)) { 397 | addr->s_addr = ina.s_addr; 398 | return (1); 399 | } 400 | 401 | return (0); 402 | } 403 | 404 | int 405 | parse_hostname(const char *word, char hostname[MAXHOSTNAMELEN]) 406 | { 407 | if (word == NULL || *word == '-') 408 | return (0); 409 | 410 | if (strlen(word) < 7 || /* shortest host is a.local */ 411 | strcmp(&word[strlen(word) - 6], ".local") != 0) { 412 | fprintf(stderr, "Invalid domain, must be .local\n"); 413 | return (0); 414 | } 415 | strlcpy(hostname, word, MAXHOSTNAMELEN); 416 | 417 | return (1); 418 | } 419 | 420 | int 421 | parse_target_hostname(const char *word, char hostname[MAXHOSTNAMELEN]) 422 | { 423 | if (word == NULL) 424 | return (0); 425 | 426 | /* XXX need to add support for host.local proxy targets, disallow for now */ 427 | if (strchr(word, '.') == NULL || 428 | strcmp(&word[strlen(word) - 6], ".local") == 0) { 429 | fprintf(stderr, "Not fully qualified unicast DNS hostname\n"); 430 | return (0); 431 | } 432 | strlcpy(hostname, word, MAXHOSTNAMELEN); 433 | 434 | return (1); 435 | } 436 | 437 | int 438 | parse_flags(const char *word, int *flags) 439 | { 440 | int r = 0; 441 | 442 | if (word == NULL || *word != '-') 443 | return (r); 444 | word++; 445 | while(*word) { 446 | switch (*word) { 447 | case 'a': 448 | *flags |= F_A; 449 | r++; 450 | break; 451 | case 'h': 452 | *flags |= F_HINFO; 453 | r++; 454 | break; 455 | case 's': 456 | *flags |= F_SRV; 457 | r++; 458 | break; 459 | case 't': 460 | *flags |= F_TXT; 461 | r++; 462 | break; 463 | default: 464 | errx(1, "unknown flag -%c", *word); 465 | } 466 | word++; 467 | } 468 | 469 | return (r); 470 | } 471 | 472 | int 473 | parse_brflags(const char *word, int *flags) 474 | { 475 | int r = 0; 476 | 477 | if (word == NULL || *word != '-') 478 | return (r); 479 | word++; 480 | while(*word) { 481 | switch (*word) { 482 | case 'r': 483 | *flags |= F_RESOLV; 484 | r++; 485 | break; 486 | case 's': 487 | *flags |= F_SCRIPT; 488 | r++; 489 | break; 490 | default: 491 | errx(1, "unknown flag -%c", *word); 492 | } 493 | word++; 494 | } 495 | 496 | return (r); 497 | } 498 | -------------------------------------------------------------------------------- /mdnsctl/parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Christiano F. Haesbaert 3 | * Copyright (c) 2006 Michele Marchetto 4 | * Copyright (c) 2004 Esben Norby 5 | * Copyright (c) 2003, 2004 Henning Brauer 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #ifndef _PARSER_H_ 21 | #define _PARSER_H_ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | /* FLAGS */ 29 | #define F_A 1 30 | #define F_HINFO 2 31 | #define F_SRV 4 32 | #define F_TXT 8 33 | #define F_PTR 16 34 | 35 | /* BRFLAGS */ 36 | #define F_RESOLV 1 37 | #define F_SCRIPT 2 38 | 39 | enum actions { 40 | NONE, 41 | LOOKUP, 42 | RLOOKUP, 43 | BROWSE_PROTO, 44 | PUBLISH, 45 | PROXY 46 | }; 47 | 48 | struct parse_result { 49 | struct in_addr addr; 50 | int flags; 51 | enum actions action; 52 | char hostname[MAXHOSTNAMELEN]; 53 | const char *proto; 54 | const char *app; 55 | const char *srvname; 56 | const char *txtstring; 57 | u_int16_t port; 58 | }; 59 | 60 | struct parse_result *parse(int, char *[]); 61 | const struct token *match_token(const char *, const struct token *); 62 | void show_valid_args(const struct token *); 63 | int parse_addr(const char *, struct in_addr *); 64 | int parse_hostname(const char *, char [MAXHOSTNAMELEN]); 65 | int parse_target_hostname(const char *, char [MAXHOSTNAMELEN]); 66 | int parse_proto(const char *, char [MAXHOSTNAMELEN]); 67 | int parse_flags(const char *, int *); 68 | int parse_brflags(const char *, int *); 69 | 70 | #endif /* _PARSER_H_ */ 71 | -------------------------------------------------------------------------------- /mdnsd/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX?=/usr/local 2 | BINDIR=${PREFIX}/bin 3 | MANDIR= ${PREFIX}/man/cat 4 | 5 | PROG= mdnsd 6 | SRCS= log.c mdnsd.c kiface.c interface.c packet.c \ 7 | control.c mdns.c 8 | 9 | MAN= mdnsd.8 10 | 11 | CFLAGS+= -g -Wall -I${.CURDIR} -I${.CURDIR}/../ 12 | CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes 13 | CFLAGS+= -Wmissing-declarations 14 | CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual 15 | CFLAGS+= -Wsign-compare 16 | 17 | .if exists(${.CURDIR}/../libmdns/${__objdir}) 18 | LDADD+= -L${.CURDIR}/../libmdns/${__objdir} -lmdns 19 | .else 20 | LDADD+= -L${.CURDIR}/../libmdns -lmdns 21 | .endif 22 | LDADD+= -levent -lutil 23 | DPADD+= ${LIBEVENT} ${LIBUTIL} 24 | 25 | .include 26 | .include 27 | -------------------------------------------------------------------------------- /mdnsd/control.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010, 2011 Christiano F. Haesbaert 3 | * Copyright (c) 2003, 2004 Henning Brauer 4 | * 5 | * Permission to use, copy, modify, and distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "mdnsd.h" 36 | #include "mdns.h" 37 | #include "log.h" 38 | #include "control.h" 39 | 40 | #define CONTROL_BACKLOG 5 41 | 42 | struct ctl_conn *control_connbyfd(int); 43 | struct ctl_conn *control_connbypid(pid_t); 44 | void control_close(int); 45 | void control_lookup(struct ctl_conn *, struct imsg *); 46 | void control_browse_add(struct ctl_conn *, struct imsg *); 47 | void control_browse_del(struct ctl_conn *, struct imsg *); 48 | void control_resolve(struct ctl_conn *, struct imsg *); 49 | void control_group_add(struct ctl_conn *, struct imsg *); 50 | void control_group_reset(struct ctl_conn *, struct imsg *); 51 | void control_group_commit(struct ctl_conn *, struct imsg *); 52 | void control_group_add_service(struct ctl_conn *, struct imsg *); 53 | 54 | extern struct mdnsd_conf *conf; 55 | 56 | void 57 | control_lookup(struct ctl_conn *c, struct imsg *imsg) 58 | { 59 | struct rrset mlkup, *rrs; 60 | struct rr *rr; 61 | struct query *q; 62 | struct timeval tv; 63 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup)) 64 | return; 65 | 66 | memcpy(&mlkup, imsg->data, sizeof(mlkup)); 67 | mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients are nice */ 68 | 69 | switch (mlkup.type) { 70 | case T_A: /* FALLTHROUGH */ 71 | case T_HINFO: /* FALLTHROUGH */ 72 | case T_PTR: /* FALLTHROUGH */ 73 | case T_SRV: /* FALLTHROUGH */ 74 | case T_TXT: /* FALLTHROUGH */ 75 | break; 76 | default: 77 | log_warnx("Lookup type %d not supported/implemented", 78 | mlkup.type); 79 | return; 80 | } 81 | 82 | if (mlkup.class != C_IN) { 83 | log_warnx("Lookup class %d not supported/implemented", 84 | mlkup.class); 85 | return; 86 | } 87 | 88 | /* Check if control has this query already, if so don't do anything */ 89 | LIST_FOREACH(q, &c->qlist, entry) { 90 | if (q->style != QUERY_LOOKUP) 91 | continue; 92 | LIST_FOREACH(rrs, &q->rrslist, entry) 93 | if (rrset_cmp(rrs, &mlkup) == 0) { 94 | log_debug("control already querying for %s", 95 | rrs_str(rrs)); 96 | return; 97 | } 98 | } 99 | 100 | log_debug("looking up %s (%s %d)", mlkup.dname, rr_type_name(mlkup.type), 101 | mlkup.class); 102 | 103 | /* 104 | * Look for answers in our cache 105 | */ 106 | rr = cache_lookup(&mlkup); 107 | /* cache hit */ 108 | if (rr != NULL) { 109 | if (control_send_rr(c, rr, IMSG_CTL_LOOKUP) == -1) 110 | log_warnx("query_answer error"); 111 | return; 112 | } 113 | 114 | if (question_add(&mlkup) == NULL) { 115 | log_warnx("Can't add question for %s (%s)", rrs_str(&mlkup)); 116 | return; 117 | } 118 | 119 | /* cache miss */ 120 | if ((q = calloc(1, sizeof(*q))) == NULL) 121 | fatal("calloc"); 122 | if ((rrs = calloc(1, sizeof(*rrs))) == NULL) 123 | fatal("calloc"); 124 | LIST_INIT(&q->rrslist); 125 | q->style = QUERY_LOOKUP; 126 | q->ctl = c; 127 | *rrs = mlkup; 128 | LIST_INSERT_HEAD(&q->rrslist, rrs, entry); 129 | LIST_INSERT_HEAD(&c->qlist, q, entry); 130 | timerclear(&tv); 131 | tv.tv_usec = FIRST_QUERYTIME; 132 | evtimer_set(&q->timer, query_fsm, q); 133 | evtimer_add(&q->timer, &tv); 134 | } 135 | 136 | void 137 | control_browse_add(struct ctl_conn *c, struct imsg *imsg) 138 | { 139 | struct rrset mlkup, *rrs; 140 | struct rr *rr; 141 | struct query *q; 142 | struct timeval tv; 143 | 144 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup)) 145 | return; 146 | 147 | memcpy(&mlkup, imsg->data, sizeof(mlkup)); 148 | mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients were nice */ 149 | 150 | if (mlkup.type != T_PTR) { 151 | log_warnx("Browse type %d not supported/implemented", 152 | mlkup.type); 153 | return; 154 | } 155 | 156 | if (mlkup.class != C_IN) { 157 | log_warnx("Browse class %d not supported/implemented", 158 | mlkup.class); 159 | return; 160 | } 161 | 162 | /* Check if control has this query already, if so don't do anything */ 163 | LIST_FOREACH(q, &c->qlist, entry) { 164 | if (q->style != QUERY_BROWSE) 165 | continue; 166 | if (rrset_cmp(q->br_ptr, &mlkup) == 0) { 167 | log_warnx("control already querying for %s", 168 | rrs_str(q->br_ptr)); 169 | return; 170 | } 171 | } 172 | 173 | log_debug("Browse add %s (%s %d)", mlkup.dname, rr_type_name(mlkup.type), 174 | mlkup.class); 175 | 176 | /* 177 | * Look for answers in our cache 178 | */ 179 | CACHE_FOREACH_RRS(rr, &mlkup) { 180 | if ((rr->flags & RR_FLAG_PUBLISHED) == 0) 181 | continue; 182 | if (control_send_rr(c, rr, IMSG_CTL_BROWSE_ADD) == -1) 183 | log_warnx("control_send_rr error 2"); 184 | } 185 | 186 | if (question_add(&mlkup) == NULL) { 187 | log_warnx("Can't add question for %s", rrs_str(&mlkup)); 188 | return; 189 | } 190 | 191 | if ((q = calloc(1, sizeof(*q))) == NULL) 192 | fatal("calloc"); 193 | if ((rrs = calloc(1, sizeof(*rrs))) == NULL) 194 | fatal("calloc"); 195 | *rrs = mlkup; 196 | LIST_INIT(&q->rrslist); 197 | q->style = QUERY_BROWSE; 198 | q->ctl = c; 199 | q->br_ptr = rrs; 200 | LIST_INSERT_HEAD(&q->rrslist, rrs, entry); 201 | LIST_INSERT_HEAD(&c->qlist, q, entry); 202 | timerclear(&tv); 203 | tv.tv_usec = FIRST_QUERYTIME; 204 | evtimer_set(&q->timer, query_fsm, q); 205 | evtimer_add(&q->timer, &tv); 206 | } 207 | 208 | void 209 | control_browse_del(struct ctl_conn *c, struct imsg *imsg) 210 | { 211 | struct rrset mlkup; 212 | struct query *q; 213 | 214 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(mlkup)) 215 | return; 216 | 217 | memcpy(&mlkup, imsg->data, sizeof(mlkup)); 218 | mlkup.dname[MAXHOSTNAMELEN - 1] = '\0'; /* assure clients were nice */ 219 | 220 | if (mlkup.type != T_PTR) { 221 | log_warnx("Browse type %d not supported/implemented", 222 | mlkup.type); 223 | return; 224 | } 225 | 226 | if (mlkup.class != C_IN) { 227 | log_warnx("Browse class %d not supported/implemented", 228 | mlkup.class); 229 | return; 230 | } 231 | 232 | LIST_FOREACH(q, &c->qlist, entry) { 233 | if (q->style != QUERY_BROWSE) 234 | continue; 235 | if (rrset_cmp(q->br_ptr, &mlkup) != 0) 236 | continue; 237 | query_remove(q); 238 | return; 239 | } 240 | 241 | log_warnx("Trying to remove non existant query"); 242 | } 243 | 244 | void 245 | control_resolve(struct ctl_conn *c, struct imsg *imsg) 246 | { 247 | char msg[MAXHOSTNAMELEN]; 248 | struct rrset *rrs_srv, *rrs_txt, *rrs_a, *rrs_aux; 249 | struct rr *srv_cache; 250 | struct query *q; 251 | struct timeval tv; 252 | 253 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) { 254 | log_warnx("control_resolve: Invalid msg len"); 255 | return; 256 | } 257 | 258 | memcpy(msg, imsg->data, sizeof(msg)); 259 | msg[sizeof(msg) - 1] = '\0'; 260 | 261 | /* Check if control has this query already, if so don't do anything */ 262 | LIST_FOREACH(q, &c->qlist, entry) { 263 | if (q->style != QUERY_RESOLVE) 264 | continue; 265 | if (strcmp(msg, q->ms_srv->dname) == 0) { 266 | log_debug("control already resolving %s", 267 | q->ms_srv->dname); 268 | return; 269 | } 270 | } 271 | 272 | log_debug("Resolve %s", msg); 273 | 274 | /* 275 | * Try getting answer withing our cache entries 276 | */ 277 | if (control_try_answer_ms(c, msg) == 1) { 278 | log_debug("Resolve for %s all in cache", msg); 279 | return; 280 | } 281 | 282 | /* 283 | * If we got here we need to make a query. 284 | */ 285 | if ((q = calloc(1, sizeof(*q))) == NULL) 286 | fatal("calloc"); 287 | LIST_INSERT_HEAD(&c->qlist, q, entry); 288 | LIST_INIT(&q->rrslist); 289 | q->style = QUERY_RESOLVE; 290 | q->ctl = c; 291 | timerclear(&tv); 292 | tv.tv_usec = FIRST_QUERYTIME; 293 | evtimer_set(&q->timer, query_fsm, q); 294 | evtimer_add(&q->timer, &tv); 295 | 296 | if ((rrs_srv = calloc(1, sizeof(*rrs_srv))) == NULL) 297 | err(1, "calloc"); 298 | if ((rrs_txt = calloc(1, sizeof(*rrs_txt))) == NULL) 299 | err(1, "calloc"); 300 | 301 | if (strlcpy(rrs_srv->dname, msg, sizeof(rrs_srv->dname)) >= 302 | sizeof(rrs_srv->dname)) { 303 | log_warnx("control_resolve: msg too long, dropping"); 304 | free(rrs_srv); 305 | free(rrs_txt); 306 | return; 307 | } 308 | rrs_srv->class = C_IN; 309 | rrs_srv->type = T_SRV; 310 | strlcpy(rrs_txt->dname, msg, sizeof(rrs_txt->dname)); 311 | rrs_txt->class = C_IN; 312 | rrs_txt->type = T_TXT; 313 | q->ms_srv = rrs_srv; 314 | LIST_INSERT_HEAD(&q->rrslist, rrs_srv, entry); 315 | LIST_INSERT_HEAD(&q->rrslist, rrs_txt, entry); 316 | if ((srv_cache = cache_lookup(rrs_srv)) != NULL) { 317 | if ((rrs_a = calloc(1, sizeof(*rrs_a))) == NULL) 318 | err(1, "calloc"); 319 | strlcpy(rrs_a->dname, srv_cache->rdata.SRV.target, 320 | sizeof(rrs_a->dname)); 321 | rrs_a->class = C_IN; 322 | rrs_a->type = T_A; 323 | q->ms_a = rrs_a; 324 | LIST_INSERT_HEAD(&q->rrslist, rrs_a, entry); 325 | } 326 | 327 | LIST_FOREACH(rrs_aux, &q->rrslist, entry) { 328 | if (question_add(rrs_aux) == NULL) { 329 | log_warnx("control_resolve: question_add error"); 330 | query_remove(q); 331 | return; 332 | } 333 | } 334 | } 335 | 336 | void 337 | control_group_add(struct ctl_conn *c, struct imsg *imsg) 338 | { 339 | char msg[MAXHOSTNAMELEN]; 340 | 341 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) { 342 | log_warnx("control_group_add: Invalid group len"); 343 | return; 344 | } 345 | 346 | memcpy(msg, imsg->data, sizeof(msg)); 347 | msg[sizeof(msg) - 1] = '\0'; 348 | /* 349 | * Check if the user hasn't already added this group, we'll issue an 350 | * error when he commits. 351 | */ 352 | if (pg_get(0, msg, c) != NULL) 353 | return; 354 | /* 355 | * Initialize group in temporary list, when user commits the group, we 356 | * will process it all. 357 | */ 358 | (void)pg_get(1, msg, c); 359 | } 360 | 361 | void 362 | control_group_add_service(struct ctl_conn *c, struct imsg *imsg) 363 | { 364 | struct pg *pg; 365 | struct pge *pge; 366 | struct mdns_service msg, *ms; 367 | 368 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) { 369 | log_warnx("control_group_add_service: Invalid group len"); 370 | return; 371 | } 372 | memcpy(&msg, imsg->data, sizeof(msg)); 373 | msg.name[sizeof(msg.name) - 1] = '\0'; 374 | ms = &msg; 375 | /* Default to ourself if target hostname not provided */ 376 | if (strlen(ms->target) == 0) 377 | (void)strlcpy(ms->target, conf->myname, sizeof(ms->target)); 378 | 379 | /* Group not found, or not newgroup commited */ 380 | pg = pg_get(0, ms->name, c); 381 | if (pg == NULL || 382 | (pg != NULL && pg->state != PG_STA_NEW)) { 383 | log_warnx("Controller trying to add service to invalid group"); 384 | return; 385 | } 386 | 387 | if ((pge = pge_from_ms(pg, ms, ALL_IFACE)) == NULL) { 388 | /* XXX assume collision */ 389 | pg->state = PG_STA_COLLISION; 390 | return; 391 | } 392 | } 393 | 394 | void 395 | control_group_reset(struct ctl_conn *c, struct imsg *imsg) 396 | { 397 | char msg[MAXHOSTNAMELEN]; 398 | struct pg *pg; 399 | 400 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) { 401 | log_warnx("control_group_reset: Invalid group len"); 402 | return; 403 | } 404 | 405 | memcpy(msg, imsg->data, sizeof(msg)); 406 | msg[sizeof(msg) - 1] = '\0'; 407 | 408 | if ((pg = pg_get(0, msg, NULL)) == NULL) { 409 | log_debug("control_group_reset: group %s not found", 410 | msg); 411 | return; 412 | } 413 | 414 | pg_kill(pg); 415 | 416 | log_debug("group %s reseted", msg); 417 | } 418 | 419 | /* 420 | * XXX revise all this, we must have a flag in group if we had a collision when 421 | * adding an entry. 422 | */ 423 | void 424 | control_group_commit(struct ctl_conn *c, struct imsg *imsg) 425 | { 426 | char msg[MAXHOSTNAMELEN]; 427 | struct pg *pg; 428 | struct pge *pge; 429 | struct timeval tv; 430 | 431 | if ((imsg->hdr.len - IMSG_HEADER_SIZE) != sizeof(msg)) { 432 | log_warnx("control_group_commit: Invalid group len"); 433 | return; 434 | } 435 | memcpy(msg, imsg->data, sizeof(msg)); 436 | msg[sizeof(msg) - 1] = '\0'; 437 | 438 | /* Check if we have the group under our control. */ 439 | pg = pg_get(0, msg, c); 440 | if (pg == NULL) { 441 | /* 442 | * If we don't, check if someone else does, if yes, we 443 | * probabably failed adding some service due to a collision, so 444 | * guess this is a collision :-), yes this is disgusting, will 445 | * fix it someday. 446 | */ 447 | TAILQ_FOREACH(pg, &pg_queue, entry) { 448 | if (strcmp(pg->name, msg) != 0) 449 | continue; 450 | control_notify_pg(c, pg, 451 | IMSG_CTL_GROUP_ERR_COLLISION); 452 | return; 453 | } 454 | 455 | control_notify_pg(c, pg, 456 | IMSG_CTL_GROUP_ERR_NOT_FOUND); 457 | return; 458 | } 459 | 460 | /* Check if we got a collision */ 461 | if (pg->state == PG_STA_COLLISION) { 462 | control_notify_pg(pg->c, pg, 463 | IMSG_CTL_GROUP_ERR_COLLISION); 464 | pg_kill(pg); 465 | return; 466 | } 467 | 468 | /* Mark we got a commit */ 469 | pg->state = PG_STA_COMMITED; 470 | 471 | timerclear(&tv); 472 | tv.tv_usec = RANDOM_PROBETIME; 473 | LIST_FOREACH(pge, &pg->pge_list, pge_entry) { 474 | pge_fsm_restart(pge, &tv); 475 | } 476 | } 477 | 478 | int 479 | control_init(void) 480 | { 481 | struct sockaddr_un sun; 482 | int fd; 483 | mode_t old_umask; 484 | 485 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 486 | log_warn("control_init: socket"); 487 | return (-1); 488 | } 489 | 490 | bzero(&sun, sizeof(sun)); 491 | sun.sun_family = AF_UNIX; 492 | strlcpy(sun.sun_path, MDNSD_SOCKET, sizeof(sun.sun_path)); 493 | 494 | if (unlink(MDNSD_SOCKET) == -1) 495 | if (errno != ENOENT) { 496 | log_warn("control_init: unlink %s", MDNSD_SOCKET); 497 | close(fd); 498 | return (-1); 499 | } 500 | 501 | old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 502 | if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 503 | log_warn("control_init: bind: %s", MDNSD_SOCKET); 504 | close(fd); 505 | umask(old_umask); 506 | return (-1); 507 | } 508 | umask(old_umask); 509 | 510 | if (chmod(MDNSD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 511 | log_warn("control_init: chmod"); 512 | close(fd); 513 | (void)unlink(MDNSD_SOCKET); 514 | return (-1); 515 | } 516 | 517 | session_socket_blockmode(fd, BM_NONBLOCK); 518 | control_state.fd = fd; 519 | 520 | return (0); 521 | } 522 | 523 | int 524 | control_listen(void) 525 | { 526 | 527 | if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 528 | log_warn("control_listen: listen"); 529 | return (-1); 530 | } 531 | 532 | event_set(&control_state.ev, control_state.fd, EV_READ | EV_PERSIST, 533 | control_accept, NULL); 534 | event_add(&control_state.ev, NULL); 535 | 536 | return (0); 537 | } 538 | 539 | void 540 | control_cleanup(void) 541 | { 542 | unlink(MDNSD_SOCKET); 543 | } 544 | 545 | void 546 | control_accept(int listenfd, short event, void *bula) 547 | { 548 | int connfd; 549 | socklen_t len; 550 | struct sockaddr_un sun; 551 | struct ctl_conn *c; 552 | 553 | len = sizeof(sun); 554 | if ((connfd = accept(listenfd, 555 | (struct sockaddr *)&sun, &len)) == -1) { 556 | if (errno != EWOULDBLOCK && errno != EINTR) 557 | log_warn("control_accept: accept"); 558 | return; 559 | } 560 | 561 | session_socket_blockmode(connfd, BM_NONBLOCK); 562 | 563 | if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { 564 | log_warn("control_accept"); 565 | close(connfd); 566 | return; 567 | } 568 | 569 | LIST_INIT(&c->qlist); 570 | imsg_init(&c->iev.ibuf, connfd); 571 | c->iev.handler = control_dispatch_imsg; 572 | c->iev.events = EV_READ; 573 | event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, 574 | c->iev.handler, &c->iev); 575 | event_add(&c->iev.ev, NULL); 576 | 577 | TAILQ_INSERT_TAIL(&ctl_conns, c, entry); 578 | } 579 | 580 | struct ctl_conn * 581 | control_connbyfd(int fd) 582 | { 583 | struct ctl_conn *c; 584 | 585 | for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.fd != fd; 586 | c = TAILQ_NEXT(c, entry)) 587 | ; /* nothing */ 588 | 589 | return (c); 590 | } 591 | 592 | struct ctl_conn * 593 | control_connbypid(pid_t pid) 594 | { 595 | struct ctl_conn *c; 596 | 597 | for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->iev.ibuf.pid != pid; 598 | c = TAILQ_NEXT(c, entry)) 599 | ; /* nothing */ 600 | 601 | return (c); 602 | } 603 | 604 | void 605 | control_close(int fd) 606 | { 607 | struct ctl_conn *c; 608 | struct query *q; 609 | struct pg *pg, *pg_next; 610 | 611 | if ((c = control_connbyfd(fd)) == NULL) { 612 | log_warn("control_close: fd %d: not found", fd); 613 | return; 614 | } 615 | msgbuf_clear(&c->iev.ibuf.w); 616 | TAILQ_REMOVE(&ctl_conns, c, entry); 617 | 618 | event_del(&c->iev.ev); 619 | close(c->iev.ibuf.fd); 620 | while ((q = LIST_FIRST(&c->qlist)) != NULL) 621 | query_remove(q); 622 | /* 623 | * Clean up all groups belonging to this controller 624 | */ 625 | for (pg = TAILQ_FIRST(&pg_queue); pg != NULL; 626 | pg = pg_next) { 627 | pg_next = TAILQ_NEXT(pg, entry); 628 | if (pg->c == c) 629 | pg_kill(pg); 630 | } 631 | free(c); 632 | } 633 | 634 | void 635 | control_dispatch_imsg(int fd, short event, void *bula) 636 | { 637 | struct ctl_conn *c; 638 | struct imsg imsg; 639 | ssize_t n; 640 | 641 | if ((c = control_connbyfd(fd)) == NULL) { 642 | log_warn("control_dispatch_imsg: fd %d: not found", fd); 643 | return; 644 | } 645 | 646 | if (event & EV_READ) { 647 | if ((n = imsg_read(&c->iev.ibuf)) == -1 || n == 0) { 648 | control_close(fd); 649 | return; 650 | } 651 | } 652 | if (event & EV_WRITE) { 653 | if (msgbuf_write(&c->iev.ibuf.w) == -1) { 654 | control_close(fd); 655 | return; 656 | } 657 | } 658 | 659 | for (;;) { 660 | if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { 661 | control_close(fd); 662 | return; 663 | } 664 | 665 | if (n == 0) 666 | break; 667 | 668 | switch (imsg.hdr.type) { 669 | case IMSG_CTL_LOOKUP: 670 | control_lookup(c, &imsg); 671 | break; 672 | case IMSG_CTL_BROWSE_ADD: 673 | control_browse_add(c, &imsg); 674 | break; 675 | case IMSG_CTL_BROWSE_DEL: 676 | control_browse_del(c, &imsg); 677 | break; 678 | case IMSG_CTL_RESOLVE: 679 | control_resolve(c, &imsg); 680 | break; 681 | case IMSG_CTL_GROUP_ADD: 682 | control_group_add(c, &imsg); 683 | break; 684 | case IMSG_CTL_GROUP_RESET: 685 | control_group_reset(c, &imsg); 686 | break; 687 | case IMSG_CTL_GROUP_COMMIT: 688 | control_group_commit(c, &imsg); 689 | break; 690 | case IMSG_CTL_GROUP_ADD_SERVICE: 691 | control_group_add_service(c, &imsg); 692 | break; 693 | default: 694 | log_debug("control_dispatch_imsg: " 695 | "error handling imsg %d", imsg.hdr.type); 696 | break; 697 | } 698 | imsg_free(&imsg); 699 | } 700 | 701 | imsg_event_add(&c->iev); 702 | } 703 | 704 | void 705 | session_socket_blockmode(int fd, enum blockmodes bm) 706 | { 707 | int flags; 708 | 709 | if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 710 | fatal("fcntl F_GETFL"); 711 | 712 | if (bm == BM_NONBLOCK) 713 | flags |= O_NONBLOCK; 714 | else 715 | flags &= ~O_NONBLOCK; 716 | 717 | if ((flags = fcntl(fd, F_SETFL, flags)) == -1) 718 | fatal("fcntl F_SETFL"); 719 | } 720 | 721 | int 722 | control_send_rr(struct ctl_conn *c, struct rr *rr, int msgtype) 723 | { 724 | int r; 725 | int inaddrany = RR_INADDRANY(rr); 726 | 727 | log_debug("control_send_rr (%s) %s", rr_type_name(rr->rrs.type), 728 | rr->rrs.dname); 729 | 730 | /* Patch up T_A with the first interface address */ 731 | if (inaddrany) 732 | rr->rdata.A.s_addr = LIST_FIRST(&conf->iface_list)->addr.s_addr; 733 | r = mdnsd_imsg_compose_ctl(c, msgtype, rr, sizeof(*rr)); 734 | if (inaddrany) 735 | rr->rdata.A.s_addr = INADDR_ANY; 736 | 737 | return (r); 738 | } 739 | 740 | int 741 | control_send_ms(struct ctl_conn *c, struct mdns_service *ms, int msgtype) 742 | { 743 | log_debug("control_send_ms %s", ms->name); 744 | 745 | return (mdnsd_imsg_compose_ctl(c, msgtype, ms, sizeof(*ms))); 746 | } 747 | 748 | /* 749 | * 1 = Success, 0 = Fail 750 | */ 751 | int 752 | control_try_answer_ms(struct ctl_conn *c, char dname[MAXHOSTNAMELEN]) 753 | { 754 | struct rr *srv, *txt, *a; 755 | struct rrset rrs; 756 | struct mdns_service ms; 757 | 758 | srv = txt = a = NULL; 759 | 760 | /* 761 | * Look for answers in our cache 762 | */ 763 | log_debug("control_try_answer_ms %s", dname); 764 | strlcpy(rrs.dname, dname, sizeof(rrs.dname)); 765 | rrs.class = C_IN; 766 | rrs.type = T_SRV; 767 | if ((srv = cache_lookup(&rrs)) == NULL) 768 | return (0); 769 | rrs.type = T_TXT; 770 | if ((txt = cache_lookup(&rrs)) == NULL) 771 | return (0); 772 | strlcpy(rrs.dname, srv->rdata.SRV.target, sizeof(rrs.dname)); 773 | rrs.type = T_A; 774 | if ((a = cache_lookup(&rrs)) == NULL) 775 | return (0); 776 | 777 | bzero(&ms, sizeof(ms)); 778 | strlcpy(ms.name, srv->rrs.dname, sizeof(ms.name)); 779 | strlcpy(ms.target, rrs.dname, sizeof(ms.target)); 780 | strlcpy(ms.txt, txt->rdata.TXT, sizeof(ms.txt)); 781 | ms.priority = srv->rdata.SRV.priority; 782 | ms.weight = srv->rdata.SRV.weight; 783 | ms.port = srv->rdata.SRV.port; 784 | /* Patch up T_A with the first interface address */ 785 | if (RR_INADDRANY(a)) 786 | ms.addr = LIST_FIRST(&conf->iface_list)->addr; 787 | else 788 | ms.addr = a->rdata.A; 789 | if (control_send_ms(c, &ms, IMSG_CTL_RESOLVE) == -1) 790 | log_warnx("control_send_ms error"); 791 | 792 | return (1); 793 | } 794 | 795 | int 796 | control_notify_pg(struct ctl_conn *c, struct pg *pg, int msgtype) 797 | { 798 | log_debug("control_notify_pg %s msg %d", pg->name, msgtype); 799 | 800 | if (c == NULL) { 801 | log_warnx("Calling control_notify_pg() with NULL !"); 802 | return (-1); 803 | } 804 | 805 | return (mdnsd_imsg_compose_ctl(c, msgtype, pg->name, 806 | sizeof(pg->name))); 807 | } 808 | -------------------------------------------------------------------------------- /mdnsd/control.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: control.h,v 1.2 2009/06/06 08:20:55 eric Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2010 Christiano F. Haesbaert 5 | * Copyright (c) 2003, 2004 Henning Brauer 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #ifndef _CONTROL_H_ 21 | #define _CONTROL_H_ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "mdnsd.h" 28 | 29 | struct { 30 | struct event ev; 31 | int fd; 32 | } control_state; 33 | 34 | enum blockmodes { 35 | BM_NORMAL, 36 | BM_NONBLOCK 37 | }; 38 | 39 | struct imsgev { 40 | struct imsgbuf ibuf; 41 | void (*handler)(int, short, void *); 42 | struct event ev; 43 | void *data; 44 | short events; 45 | }; 46 | 47 | struct ctl_conn { 48 | TAILQ_ENTRY(ctl_conn) entry; 49 | struct imsgev iev; 50 | LIST_HEAD(, query) qlist; 51 | }; 52 | 53 | int control_init(void); 54 | int control_listen(void); 55 | void control_accept(int, short, void *); 56 | void control_dispatch_imsg(int, short, void *); 57 | void control_cleanup(void); 58 | 59 | void session_socket_blockmode(int, enum blockmodes); 60 | 61 | #endif /* _CONTROL_H_ */ 62 | -------------------------------------------------------------------------------- /mdnsd/interface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Michele Marchetto 3 | * Copyright (c) 2005 Claudio Jeker 4 | * Copyright (c) 2004, 2005 Esben Norby 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "mdnsd.h" 36 | #include "log.h" 37 | 38 | extern struct mdnsd_conf *conf; 39 | 40 | int if_act_start(struct iface *); 41 | int if_act_reset(struct iface *); 42 | 43 | struct { 44 | int state; 45 | enum iface_event event; 46 | enum iface_action action; 47 | int new_state; 48 | } iface_fsm[] = { 49 | /* current state event that happened action to take resulting state */ 50 | {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0}, 51 | {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN}, 52 | {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0}, 53 | }; 54 | 55 | const char * const if_action_names[] = { 56 | "NOTHING", 57 | "START", 58 | "RESET" 59 | }; 60 | 61 | const char * const if_event_names[] = { 62 | "NOTHING", 63 | "UP", 64 | "DOWN", 65 | }; 66 | 67 | int 68 | if_fsm(struct iface *iface, enum iface_event event) 69 | { 70 | int old_state; 71 | int new_state = 0; 72 | int i, ret = 0; 73 | 74 | old_state = iface->state; 75 | 76 | for (i = 0; iface_fsm[i].state != -1; i++) 77 | if ((iface_fsm[i].state & old_state) && 78 | (iface_fsm[i].event == event)) { 79 | new_state = iface_fsm[i].new_state; 80 | break; 81 | } 82 | 83 | if (iface_fsm[i].state == -1) { 84 | /* event outside of the defined fsm, ignore it. */ 85 | log_debug("if_fsm: interface %s, " 86 | "event '%s' not expected in state '%s'", iface->name, 87 | if_event_name(event), if_state_name(old_state)); 88 | return (0); 89 | } 90 | 91 | switch (iface_fsm[i].action) { 92 | case IF_ACT_STRT: 93 | ret = if_act_start(iface); 94 | break; 95 | case IF_ACT_RST: 96 | ret = if_act_reset(iface); 97 | break; 98 | case IF_ACT_NOTHING: 99 | /* do nothing */ 100 | break; 101 | } 102 | 103 | if (ret) { 104 | log_debug("if_fsm: error changing state for interface %s, " 105 | "event '%s', state '%s'", iface->name, if_event_name(event), 106 | if_state_name(old_state)); 107 | return (0); 108 | } 109 | 110 | if (new_state != 0) 111 | iface->state = new_state; 112 | 113 | log_debug("if_fsm: event '%s' resulted in action '%s' and changing " 114 | "state for interface %s from '%s' to '%s'", 115 | if_event_name(event), if_action_name(iface_fsm[i].action), 116 | iface->name, if_state_name(old_state), if_state_name(iface->state)); 117 | 118 | return (ret); 119 | } 120 | 121 | struct iface * 122 | if_find_index(u_short ifindex) 123 | { 124 | struct iface *iface; 125 | 126 | LIST_FOREACH(iface, &conf->iface_list, entry) { 127 | if (iface->ifindex == ifindex) 128 | return (iface); 129 | } 130 | 131 | return (NULL); 132 | } 133 | 134 | struct iface * 135 | if_find_iface(unsigned int ifindex, struct in_addr src) 136 | { 137 | struct iface *iface = NULL; 138 | 139 | /* returned interface needs to be active */ 140 | LIST_FOREACH(iface, &conf->iface_list, entry) { 141 | if (ifindex != 0 && ifindex == iface->ifindex && 142 | (iface->addr.s_addr & iface->mask.s_addr) == 143 | (src.s_addr & iface->mask.s_addr)) 144 | /* 145 | * XXX may fail on P2P links because src and dst don't 146 | * have to share a common subnet on the otherhand 147 | * checking something like this will help to support 148 | * multiple networks configured on one interface. 149 | */ 150 | return (iface); 151 | } 152 | 153 | return (NULL); 154 | } 155 | 156 | /* actions */ 157 | int 158 | if_act_start(struct iface *iface) 159 | { 160 | struct in_addr addr; 161 | struct timeval now; 162 | 163 | if (!((iface->flags & IFF_UP) && 164 | (LINK_STATE_IS_UP(iface->linkstate) || 165 | (iface->linkstate == LINK_STATE_UNKNOWN && 166 | iface->media_type != IFT_CARP)))) { 167 | log_debug("if_act_start: interface %s link down", 168 | iface->name); 169 | return (0); 170 | } 171 | 172 | gettimeofday(&now, NULL); 173 | iface->uptime = now.tv_sec; 174 | 175 | switch (iface->type) { 176 | case IF_TYPE_POINTOPOINT: 177 | case IF_TYPE_BROADCAST: 178 | inet_aton(ALL_MDNS_DEVICES, &addr); 179 | if (if_join_group(iface, &addr)) { 180 | log_warn("if_act_start: error joining group %s, " 181 | "interface %s", inet_ntoa(addr), iface->name); 182 | return (-1); 183 | } 184 | 185 | iface->state = IF_STA_ACTIVE; 186 | break; 187 | default: 188 | fatalx("if_act_start: unknown interface type"); 189 | } 190 | 191 | /* publish all groups on this interface */ 192 | pg_publish_byiface(iface); 193 | 194 | return (0); 195 | } 196 | 197 | int 198 | if_act_reset(struct iface *iface) 199 | { 200 | struct in_addr addr; 201 | 202 | switch (iface->type) { 203 | case IF_TYPE_POINTOPOINT: 204 | case IF_TYPE_BROADCAST: 205 | inet_aton(ALL_MDNS_DEVICES, &addr); 206 | if (if_leave_group(iface, &addr)) { 207 | log_warn("if_act_reset: error leaving group %s, " 208 | "interface %s", inet_ntoa(addr), iface->name); 209 | } 210 | break; 211 | default: 212 | fatalx("if_act_reset: unknown interface type"); 213 | } 214 | 215 | return (0); 216 | } 217 | 218 | const char * 219 | if_event_name(int event) 220 | { 221 | return (if_event_names[event]); 222 | } 223 | 224 | const char * 225 | if_action_name(int action) 226 | { 227 | return (if_action_names[action]); 228 | } 229 | 230 | /* misc */ 231 | int 232 | if_set_mcast_ttl(int fd, u_int8_t ttl) 233 | { 234 | if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, 235 | (char *)&ttl, sizeof(ttl)) < 0) { 236 | log_warn("if_set_mcast_ttl: error setting " 237 | "IP_MULTICAST_TTL to %d", ttl); 238 | return (-1); 239 | } 240 | 241 | return (0); 242 | } 243 | 244 | int 245 | if_set_opt(int fd) 246 | { 247 | int yes = 1; 248 | 249 | if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &yes, 250 | sizeof(int)) < 0) { 251 | log_warn("if_set_opt: error setting IP_RECVIF"); 252 | return (-1); 253 | } 254 | 255 | if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &yes, 256 | sizeof(int)) < 0) { 257 | log_warn("if_set_opt: error setting IP_RECVDSTADDR"); 258 | return (-1); 259 | } 260 | 261 | return (0); 262 | } 263 | 264 | int 265 | if_set_tos(int fd, int tos) 266 | { 267 | if (setsockopt(fd, IPPROTO_IP, IP_TOS, 268 | (int *)&tos, sizeof(tos)) < 0) { 269 | log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos); 270 | return (-1); 271 | } 272 | 273 | return (0); 274 | } 275 | 276 | int 277 | if_set_mcast(struct iface *iface) 278 | { 279 | switch (iface->type) { 280 | case IF_TYPE_POINTOPOINT: 281 | case IF_TYPE_BROADCAST: 282 | if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF, 283 | &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) { 284 | log_debug("if_set_mcast: error setting " 285 | "IP_MULTICAST_IF, interface %s", iface->name); 286 | return (-1); 287 | } 288 | break; 289 | default: 290 | fatalx("if_set_mcast: unknown interface type"); 291 | } 292 | 293 | return (0); 294 | } 295 | 296 | int 297 | if_set_mcast_loop(int fd) 298 | { 299 | u_int8_t loop = 0; 300 | 301 | if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 302 | (char *)&loop, sizeof(loop)) < 0) { 303 | log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP"); 304 | return (-1); 305 | } 306 | 307 | return (0); 308 | } 309 | 310 | void 311 | if_set_recvbuf(int fd) 312 | { 313 | int bsize; 314 | 315 | bsize = 65535; 316 | while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize, 317 | sizeof(bsize)) == -1) 318 | bsize /= 2; 319 | } 320 | 321 | int 322 | if_join_group(struct iface *iface, struct in_addr *addr) 323 | { 324 | struct ip_mreq mreq; 325 | 326 | switch (iface->type) { 327 | case IF_TYPE_POINTOPOINT: 328 | case IF_TYPE_BROADCAST: 329 | mreq.imr_multiaddr.s_addr = addr->s_addr; 330 | mreq.imr_interface.s_addr = iface->addr.s_addr; 331 | 332 | if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 333 | (void *)&mreq, sizeof(mreq)) < 0) 334 | return (-1); 335 | break; 336 | default: 337 | fatalx("if_join_group: unknown interface type"); 338 | } 339 | 340 | return (0); 341 | } 342 | 343 | int 344 | if_leave_group(struct iface *iface, struct in_addr *addr) 345 | { 346 | struct ip_mreq mreq; 347 | 348 | switch (iface->type) { 349 | case IF_TYPE_POINTOPOINT: 350 | case IF_TYPE_BROADCAST: 351 | mreq.imr_multiaddr.s_addr = addr->s_addr; 352 | mreq.imr_interface.s_addr = iface->addr.s_addr; 353 | 354 | if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 355 | (void *)&mreq, sizeof(mreq)) < 0) 356 | return (-1); 357 | break; 358 | default: 359 | fatalx("if_leave_group: unknown interface type"); 360 | } 361 | 362 | return (0); 363 | } 364 | 365 | struct iface * 366 | if_new(struct kif *kif) 367 | { 368 | struct sockaddr_in *sain; 369 | struct iface *iface; 370 | struct ifreq *ifr; 371 | int s; 372 | int succeed = 0; 373 | 374 | if ((iface = calloc(1, sizeof(*iface))) == NULL) 375 | err(1, "if_new: calloc"); 376 | 377 | iface->state = IF_STA_DOWN; 378 | 379 | strlcpy(iface->name, kif->ifname, sizeof(iface->name)); 380 | 381 | if ((ifr = calloc(1, sizeof(*ifr))) == NULL) 382 | err(1, "if_new: calloc"); 383 | 384 | /* set up ifreq */ 385 | strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name)); 386 | if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 387 | err(1, "if_new: socket"); 388 | 389 | /* get type */ 390 | if (kif->flags & IFF_POINTOPOINT) 391 | iface->type = IF_TYPE_POINTOPOINT; 392 | if (kif->flags & IFF_BROADCAST && 393 | kif->flags & IFF_MULTICAST) 394 | iface->type = IF_TYPE_BROADCAST; 395 | if (kif->flags & IFF_LOOPBACK) { 396 | iface->type = IF_TYPE_POINTOPOINT; 397 | /* XXX protect loopback from sending packets over lo? */ 398 | } 399 | 400 | /* get mtu, index and flags */ 401 | iface->mtu = kif->mtu; 402 | iface->ifindex = kif->ifindex; 403 | iface->flags = kif->flags; 404 | iface->linkstate = kif->link_state; 405 | iface->media_type = kif->media_type; 406 | iface->baudrate = kif->baudrate; 407 | iface->ea = kif->ea; 408 | 409 | /* get address */ 410 | if (ioctl(s, SIOCGIFADDR, ifr) < 0) { 411 | log_warn("if_new: cannot get address"); 412 | goto end; 413 | } 414 | sain = (struct sockaddr_in *)&ifr->ifr_addr; 415 | iface->addr = sain->sin_addr; 416 | 417 | /* get mask */ 418 | if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) { 419 | log_warn("if_new: cannot get mask"); 420 | goto end; 421 | } 422 | sain = (struct sockaddr_in *)&ifr->ifr_addr; 423 | iface->mask = sain->sin_addr; 424 | 425 | /* get p2p dst address */ 426 | if (kif->flags & IFF_POINTOPOINT) { 427 | if (ioctl(s, SIOCGIFDSTADDR, ifr) < 0) { 428 | log_warn("if_new: cannot get dst addr"); 429 | goto end; 430 | } 431 | sain = (struct sockaddr_in *)&ifr->ifr_addr; 432 | iface->dst = sain->sin_addr; 433 | } 434 | 435 | /* get the primary group for this interface */ 436 | if (conf->no_workstation == 0) 437 | iface->pge_workstation = pge_new_workstation(iface); 438 | 439 | succeed = 1; 440 | 441 | end: 442 | if (!succeed) { 443 | free(iface); 444 | iface = NULL; 445 | } 446 | 447 | free(ifr); 448 | close(s); 449 | 450 | return (iface); 451 | } 452 | -------------------------------------------------------------------------------- /mdnsd/kiface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Christiano F. Haesbaert 3 | * Copyright (c) 2004 Esben Norby 4 | * Copyright (c) 2003, 2004 Henning Brauer 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | /* The following is a very stripped down version of ripd's kroute.c */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "mdnsd.h" 43 | #include "log.h" 44 | 45 | #define RT_BUF_SIZE 16384 46 | #define MAX_RTSOCK_BUF 128 * 1024 47 | 48 | struct kif_node { 49 | RB_ENTRY(kif_node) entry; 50 | struct kif k; 51 | }; 52 | 53 | void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 54 | int kif_compare(struct kif_node *, struct kif_node *); 55 | int kif_insert(struct kif_node *); 56 | int fetchifs(int); 57 | void kev_dispatch_msg(int, short, void *); 58 | 59 | struct { 60 | int fd; 61 | struct event ev; 62 | } kev_state; 63 | 64 | 65 | RB_HEAD(kif_tree, kif_node) kit; 66 | RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare); 67 | RB_GENERATE(kif_tree, kif_node, entry, kif_compare); 68 | 69 | int 70 | kif_init(void) 71 | { 72 | RB_INIT(&kit); 73 | 74 | if (fetchifs(0) == -1) 75 | return (-1); 76 | 77 | return (0); 78 | } 79 | 80 | struct kif * 81 | kif_findname(char *ifname) 82 | { 83 | struct kif_node *kif; 84 | 85 | RB_FOREACH(kif, kif_tree, &kit) 86 | if (!strcmp(ifname, kif->k.ifname)) 87 | return (&kif->k); 88 | 89 | return (NULL); 90 | } 91 | 92 | int 93 | kif_insert(struct kif_node *kif) 94 | { 95 | if (RB_INSERT(kif_tree, &kit, kif) != NULL) { 96 | log_warnx("RB_INSERT(kif_tree, &kit, kif)"); 97 | free(kif); 98 | return (-1); 99 | } 100 | 101 | return (0); 102 | } 103 | 104 | int 105 | kif_compare(struct kif_node *a, struct kif_node *b) 106 | { 107 | return (b->k.ifindex - a->k.ifindex); 108 | } 109 | 110 | #define ROUNDUP(a, size) \ 111 | (((a) & ((size) - 1)) ? (1 + ((a) | ((size) - 1))) : (a)) 112 | 113 | void 114 | kif_cleanup(void) 115 | { 116 | /* TODO */ 117 | } 118 | 119 | void 120 | get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 121 | { 122 | int i; 123 | 124 | for (i = 0; i < RTAX_MAX; i++) { 125 | if (addrs & (1 << i)) { 126 | rti_info[i] = sa; 127 | sa = (struct sockaddr *)((char *)(sa) + 128 | ROUNDUP(sa->sa_len, sizeof(long))); 129 | } else 130 | rti_info[i] = NULL; 131 | } 132 | } 133 | 134 | int 135 | fetchifs(int ifindex) 136 | { 137 | size_t len; 138 | int mib[6]; 139 | char *buf, *next, *lim; 140 | struct if_msghdr ifm; 141 | struct kif_node *kif; 142 | struct sockaddr *sa, *rti_info[RTAX_MAX]; 143 | struct sockaddr_dl *sdl; 144 | 145 | mib[0] = CTL_NET; 146 | mib[1] = AF_ROUTE; 147 | mib[2] = 0; 148 | mib[3] = AF_INET; 149 | mib[4] = NET_RT_IFLIST; 150 | mib[5] = ifindex; 151 | 152 | if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) { 153 | log_warn("sysctl"); 154 | return (-1); 155 | } 156 | if ((buf = malloc(len)) == NULL) { 157 | log_warn("fetchif"); 158 | return (-1); 159 | } 160 | if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) { 161 | log_warn("sysctl"); 162 | free(buf); 163 | return (-1); 164 | } 165 | 166 | lim = buf + len; 167 | for (next = buf; next < lim; next += ifm.ifm_msglen) { 168 | memcpy(&ifm, next, sizeof(ifm)); 169 | if (ifm.ifm_version != RTM_VERSION) 170 | continue; 171 | if (ifm.ifm_type != RTM_IFINFO) 172 | continue; 173 | 174 | sa = (struct sockaddr *)(next + sizeof(ifm)); 175 | get_rtaddrs(ifm.ifm_addrs, sa, rti_info); 176 | 177 | if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) { 178 | log_warn("fetchifs"); 179 | free(buf); 180 | return (-1); 181 | } 182 | 183 | kif->k.ifindex = ifm.ifm_index; 184 | kif->k.flags = ifm.ifm_flags; 185 | kif->k.link_state = ifm.ifm_data.ifi_link_state; 186 | kif->k.media_type = ifm.ifm_data.ifi_type; 187 | kif->k.baudrate = ifm.ifm_data.ifi_baudrate; 188 | kif->k.mtu = ifm.ifm_data.ifi_mtu; 189 | if ((sa = rti_info[RTAX_IFP]) != NULL) 190 | if (sa->sa_family == AF_LINK) { 191 | sdl = (struct sockaddr_dl *)sa; 192 | if (sdl->sdl_nlen >= sizeof(kif->k.ifname)) 193 | memcpy(kif->k.ifname, sdl->sdl_data, 194 | sizeof(kif->k.ifname) - 1); 195 | else if (sdl->sdl_nlen > 0) 196 | memcpy(kif->k.ifname, sdl->sdl_data, 197 | sdl->sdl_nlen); 198 | if (sdl->sdl_alen > 0) { 199 | if (sdl->sdl_alen != ETHER_ADDR_LEN) 200 | log_warnx("sdl->sdl_alen = %u\n", 201 | sdl->sdl_alen); 202 | memcpy(&kif->k.ea, 203 | sdl->sdl_data + sdl->sdl_nlen, 204 | MIN(sizeof(kif->k.ea), 205 | sdl->sdl_alen)); 206 | } 207 | 208 | /* string already terminated via calloc() */ 209 | } 210 | kif_insert(kif); 211 | } 212 | free(buf); 213 | return (0); 214 | } 215 | 216 | void 217 | kev_init(void) 218 | { 219 | int opt = 0, rcvbuf, default_rcvbuf; 220 | socklen_t optlen; 221 | 222 | if ((kev_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) 223 | fatal("kev_init: socket"); 224 | 225 | log_debug("opened raw socket with kernel on fd %d", kev_state.fd); 226 | 227 | /* not interested in my own messages */ 228 | if (setsockopt(kev_state.fd, SOL_SOCKET, SO_USELOOPBACK, 229 | &opt, sizeof(opt)) == -1) 230 | log_warn("kev: setsockopt"); /* not fatal ? why ? */ 231 | 232 | /* grow receive buffer, don't wanna miss messages */ 233 | optlen = sizeof(default_rcvbuf); 234 | if (getsockopt(kev_state.fd, SOL_SOCKET, SO_RCVBUF, 235 | &default_rcvbuf, &optlen) == -1) 236 | log_warn("kev_init getsockopt SOL_SOCKET SO_RCVBUF"); 237 | else 238 | for (rcvbuf = MAX_RTSOCK_BUF; 239 | rcvbuf > default_rcvbuf && 240 | setsockopt(kev_state.fd, SOL_SOCKET, SO_RCVBUF, 241 | &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS; 242 | rcvbuf /= 2) 243 | ; /* nothing */ 244 | 245 | event_set(&kev_state.ev, kev_state.fd, EV_READ | EV_PERSIST, 246 | kev_dispatch_msg, NULL); 247 | event_add(&kev_state.ev, NULL); 248 | } 249 | 250 | /* ARGSNOTUSED */ 251 | void 252 | kev_dispatch_msg(int fd, short event, void *bula) 253 | { 254 | char buf[RT_BUF_SIZE]; 255 | char *next, *lim; 256 | ssize_t n; 257 | struct rt_msghdr *rtm; 258 | struct if_msghdr ifm; 259 | struct iface *iface; 260 | 261 | if ((n = read(kev_state.fd, &buf, sizeof(buf))) == -1) 262 | fatal("kev_dispatch_rtmsg: read error"); 263 | 264 | if (n == 0) 265 | fatalx("kernel event socket closed"); 266 | 267 | lim = buf + n; 268 | for (next = buf; next < lim; next += rtm->rtm_msglen) { 269 | memcpy(&ifm, next, sizeof(ifm)); 270 | rtm = (struct rt_msghdr *)next; 271 | if (rtm->rtm_version != RTM_VERSION) 272 | continue; 273 | 274 | iface = if_find_index(ifm.ifm_index); 275 | if (iface == NULL) /* this interface isn't configured */ 276 | continue; 277 | 278 | switch (rtm->rtm_type) { 279 | case RTM_IFINFO: 280 | log_debug("RTM_IFINFO"); 281 | if (LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state)) 282 | if_fsm(iface, IF_EVT_UP); 283 | else 284 | if_fsm(iface, IF_EVT_DOWN); 285 | break; 286 | case RTM_IFANNOUNCE: 287 | log_debug("RTM_IFANNOUNCE"); 288 | break; 289 | case RTM_NEWADDR: 290 | /* XXX this is SO wrong */ 291 | if_fsm(iface, IF_EVT_UP); 292 | log_debug("RTM_NEWADDR"); 293 | break; 294 | case RTM_DELADDR: 295 | /* XXX this is SO wrong */ 296 | log_debug("RTM_DELADDR"); 297 | if_fsm(iface, IF_EVT_DOWN); 298 | break; 299 | default: 300 | /* ignore for now */ 301 | break; 302 | } 303 | } 304 | } 305 | 306 | void 307 | kev_cleanup(void) 308 | { 309 | /* TODO */ 310 | } 311 | -------------------------------------------------------------------------------- /mdnsd/log.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: log.c,v 1.6 2009/11/02 20:20:54 claudio Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2003, 2004 Henning Brauer 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "log.h" 34 | #include "mdnsd.h" 35 | 36 | int debug; 37 | int verbose; 38 | 39 | void logit(int, const char *, ...); 40 | 41 | #ifndef S 42 | #define S(a) #a 43 | #endif 44 | 45 | #define LOG_DEBUG_STRUCT(x, field, how) \ 46 | log_debug("%s = " S(how), S(field), x->field) 47 | 48 | void 49 | log_init(int n_debug) 50 | { 51 | extern char *__progname; 52 | 53 | debug = n_debug; 54 | verbose = n_debug; 55 | 56 | if (!debug) 57 | openlog(__progname, LOG_NDELAY, LOG_DAEMON); 58 | 59 | tzset(); 60 | } 61 | 62 | void 63 | log_verbose(int v) 64 | { 65 | verbose = v; 66 | } 67 | 68 | void 69 | logit(int pri, const char *fmt, ...) 70 | { 71 | va_list ap; 72 | 73 | va_start(ap, fmt); 74 | vlog(pri, fmt, ap); 75 | va_end(ap); 76 | } 77 | 78 | void 79 | vlog(int pri, const char *fmt, va_list ap) 80 | { 81 | char *nfmt; 82 | 83 | if (debug) { 84 | /* best effort in out of mem situations */ 85 | if (asprintf(&nfmt, "%s\n", fmt) == -1) { 86 | vfprintf(stderr, fmt, ap); 87 | fprintf(stderr, "\n"); 88 | } else { 89 | vfprintf(stderr, nfmt, ap); 90 | free(nfmt); 91 | } 92 | fflush(stderr); 93 | } else 94 | vsyslog(pri, fmt, ap); 95 | } 96 | 97 | void 98 | log_warn(const char *emsg, ...) 99 | { 100 | char *nfmt; 101 | va_list ap; 102 | 103 | /* best effort to even work in out of memory situations */ 104 | if (emsg == NULL) 105 | logit(LOG_CRIT, "%s", strerror(errno)); 106 | else { 107 | va_start(ap, emsg); 108 | 109 | if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { 110 | /* we tried it... */ 111 | vlog(LOG_CRIT, emsg, ap); 112 | logit(LOG_CRIT, "%s", strerror(errno)); 113 | } else { 114 | vlog(LOG_CRIT, nfmt, ap); 115 | free(nfmt); 116 | } 117 | va_end(ap); 118 | } 119 | } 120 | 121 | void 122 | log_warnx(const char *emsg, ...) 123 | { 124 | va_list ap; 125 | 126 | va_start(ap, emsg); 127 | vlog(LOG_CRIT, emsg, ap); 128 | va_end(ap); 129 | } 130 | 131 | void 132 | log_info(const char *emsg, ...) 133 | { 134 | va_list ap; 135 | 136 | va_start(ap, emsg); 137 | vlog(LOG_INFO, emsg, ap); 138 | va_end(ap); 139 | } 140 | 141 | void 142 | log_debug(const char *emsg, ...) 143 | { 144 | va_list ap; 145 | 146 | if (verbose) { 147 | va_start(ap, emsg); 148 | vlog(LOG_DEBUG, emsg, ap); 149 | va_end(ap); 150 | } 151 | } 152 | 153 | void 154 | fatal(const char *emsg) 155 | { 156 | if (emsg == NULL) 157 | logit(LOG_CRIT, "fatal: %s", strerror(errno)); 158 | else 159 | if (errno) 160 | logit(LOG_CRIT, "fatal: %s: %s", 161 | emsg, strerror(errno)); 162 | else 163 | logit(LOG_CRIT, "fatal: %s", emsg); 164 | 165 | exit(1); 166 | } 167 | 168 | void 169 | fatalx(const char *emsg) 170 | { 171 | errno = 0; 172 | fatal(emsg); 173 | } 174 | 175 | const char * 176 | if_state_name(int state) 177 | { 178 | switch (state) { 179 | case IF_STA_DOWN: 180 | return ("DOWN"); 181 | case IF_STA_ACTIVE: 182 | return ("ACTIVE"); 183 | default: 184 | return ("UNKNOWN"); 185 | } 186 | } 187 | 188 | const char * 189 | rr_type_name(uint16_t type) 190 | { 191 | switch(type) { 192 | case T_ANY: 193 | return "ANY"; /* NOTREACHED */ 194 | break; 195 | case T_A: 196 | return "A"; 197 | break; /* NOTREACHED */ 198 | case T_AAAA: 199 | return "AAAA"; 200 | break; /* NOTREACHED */ 201 | case T_HINFO: 202 | return "HINFO"; 203 | break; /* NOTREACHED */ 204 | case T_CNAME: 205 | return "CNAME"; 206 | break; /* NOTREACHED */ 207 | case T_PTR: 208 | return "PTR"; 209 | break; /* NOTREACHED */ 210 | case T_SRV: 211 | return "SRV"; 212 | break; /* NOTREACHED */ 213 | case T_TXT: 214 | return "TXT"; 215 | break; /* NOTREACHED */ 216 | case T_NS: 217 | return "NS"; 218 | break; /* NOTREACHED */ 219 | case T_NSEC: 220 | return "NSEC"; 221 | break; /* NOTREACHED */ 222 | case T_OPT: 223 | return "OPT"; 224 | break; /* NOTREACHED */ 225 | case T_NULL: 226 | return "NULL"; 227 | break; /* NOTREACHED */ 228 | default: 229 | log_debug("Unknown %d", type); 230 | break; /* NOTREACHED */ 231 | } 232 | 233 | return "Unknown"; 234 | } 235 | 236 | void 237 | log_debug_rr(struct rr *rr) 238 | { 239 | log_debug("-->%s (%s)", rr->rrs.dname, rr_type_name(rr->rrs.type)); 240 | 241 | switch(rr->rrs.type) { 242 | case T_A: 243 | log_debug("\t %s", inet_ntoa(rr->rdata.A)); 244 | break; 245 | case T_HINFO: 246 | log_debug("\t cpu: %s", rr->rdata.HINFO.cpu); 247 | log_debug("\t os: %s", rr->rdata.HINFO.os); 248 | break; 249 | case T_CNAME: 250 | log_debug("\t %s", rr->rdata.CNAME); 251 | break; 252 | case T_PTR: 253 | log_debug("\t %s", rr->rdata.PTR); 254 | break; 255 | case T_SRV: 256 | log_debug("\t priority: %u", rr->rdata.SRV.priority); 257 | log_debug("\t weight: %u", rr->rdata.SRV.weight); 258 | log_debug("\t port: %u", rr->rdata.SRV.port); 259 | log_debug("\t target: %s", rr->rdata.SRV.target); 260 | break; 261 | case T_TXT: 262 | log_debug("\t %s", rr->rdata.TXT); 263 | break; 264 | case T_NS: 265 | log_debug("\t %s", rr->rdata.NS); 266 | break; 267 | case T_AAAA: 268 | log_debug("\t implement me"); 269 | break; 270 | default: 271 | log_debug("log_debug_rr: Unknown rr type"); 272 | break; 273 | } 274 | log_debug("<--"); 275 | } 276 | 277 | char * 278 | rrs_str(struct rrset *rrs) 279 | { 280 | static char buf[512]; 281 | 282 | snprintf(buf, sizeof(buf), "%s (%s)", rrs->dname, 283 | rr_type_name(rrs->type)); 284 | buf[sizeof(buf) - 1] = '\0'; 285 | 286 | return (buf); 287 | } 288 | -------------------------------------------------------------------------------- /mdnsd/log.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: log.h,v 1.5 2009/11/02 20:20:54 claudio Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2003, 2004 Henning Brauer 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef _LOG_H_ 20 | #define _LOG_H_ 21 | 22 | #include 23 | 24 | #include "mdnsd.h" 25 | 26 | void log_init(int); 27 | void log_verbose(int); 28 | void vlog(int, const char *, va_list); 29 | void log_warn(const char *, ...); 30 | void log_warnx(const char *, ...); 31 | void log_info(const char *, ...); 32 | void log_debug(const char *, ...); 33 | void log_debug_rr(struct rr *); 34 | void fatal(const char *) __dead; 35 | void fatalx(const char *) __dead; 36 | const char * if_state_name(int); 37 | const char * if_type_name(enum iface_type); 38 | const char * if_action_name(int); 39 | const char * rr_type_name(uint16_t); 40 | char * rrs_str(struct rrset *); 41 | 42 | #endif /* _LOG_H_ */ 43 | -------------------------------------------------------------------------------- /mdnsd/mdns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Christiano F. Haesbaert 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | * This is the header shared between applications and the daemon, it will be on 19 | * a library someday so keep it clean, we'll need to fix all 20 | * symbol prefixes someday. 21 | */ 22 | #ifndef _MDNS_H_ 23 | #define _MDNS_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #define MAXCHARSTR MAXHOSTNAMELEN 35 | #define MAXLABELLEN 64 36 | #define MAXPROTOLEN 4 37 | #define MDNSD_SOCKET "/var/run/mdnsd.sock" 38 | 39 | enum imsg_type { 40 | IMSG_NONE, 41 | IMSG_CTL_END, 42 | IMSG_CTL_LOOKUP, 43 | IMSG_CTL_LOOKUP_FAILURE, 44 | IMSG_CTL_BROWSE_ADD, 45 | IMSG_CTL_BROWSE_DEL, 46 | IMSG_CTL_RESOLVE, 47 | IMSG_CTL_RESOLVE_FAILURE, 48 | IMSG_CTL_GROUP_ADD, 49 | IMSG_CTL_GROUP_RESET, 50 | IMSG_CTL_GROUP_ADD_SERVICE, 51 | IMSG_CTL_GROUP_COMMIT, 52 | IMSG_CTL_GROUP_ERR_COLLISION, 53 | IMSG_CTL_GROUP_ERR_NOT_FOUND, 54 | IMSG_CTL_GROUP_ERR_DOUBLE_ADD, 55 | IMSG_CTL_GROUP_PROBING, 56 | IMSG_CTL_GROUP_ANNOUNCING, 57 | IMSG_CTL_GROUP_PUBLISHED, 58 | }; 59 | 60 | enum client_events { 61 | MDNS_LOOKUP_SUCCESS, 62 | MDNS_LOOKUP_FAILURE, 63 | MDNS_SERVICE_DOWN, 64 | MDNS_SERVICE_UP, 65 | MDNS_RESOLVE_SUCCESS, 66 | MDNS_RESOLVE_FAILURE, 67 | MDNS_GROUP_ERR_COLLISION, 68 | MDNS_GROUP_ERR_NOT_FOUND, 69 | MDNS_GROUP_ERR_DOUBLE_ADD, 70 | MDNS_GROUP_PROBING, 71 | MDNS_GROUP_ANNOUNCING, 72 | MDNS_GROUP_PUBLISHED, 73 | }; 74 | 75 | struct mdns; 76 | struct mdns_service; 77 | typedef void (*browse_hook) (struct mdns *, int event, const char *name, 78 | const char *app, const char *proto); 79 | typedef void (*resolve_hook) (struct mdns *, int event, struct mdns_service *); 80 | typedef void (*lookup_A_hook) (struct mdns *, int event, const char *name, 81 | struct in_addr address); 82 | typedef void (*lookup_PTR_hook) (struct mdns *, int event, const char *name, 83 | const char *ptr); 84 | typedef void (*lookup_HINFO_hook) (struct mdns *, int event, const char *name, 85 | const char *cpu, const char *os); 86 | typedef void (*group_hook) (struct mdns *, int event, const char *name); 87 | 88 | /* Accepted RR: A, HINFO, CNAME, PTR, SRV, TXT, NS */ 89 | struct mdns_service { 90 | LIST_ENTRY(mdns_service) entry; 91 | char app[MAXLABELLEN]; 92 | char proto[MAXPROTOLEN]; 93 | char name[MAXHOSTNAMELEN]; 94 | char target[MAXHOSTNAMELEN]; 95 | u_int16_t priority; 96 | u_int16_t weight; 97 | u_int16_t port; 98 | char txt[MAXCHARSTR]; 99 | struct in_addr addr; 100 | }; 101 | 102 | /* TODO browse_udata and group_udata */ 103 | struct mdns { 104 | struct imsgbuf ibuf; 105 | browse_hook bhk; 106 | lookup_A_hook lhk_A; 107 | lookup_PTR_hook lhk_PTR; 108 | lookup_HINFO_hook lhk_HINFO; 109 | resolve_hook rhk; 110 | group_hook ghk; 111 | void *udata; 112 | }; 113 | 114 | int mdns_browse_add(struct mdns *, const char *, const char *); 115 | int mdns_browse_del(struct mdns *, const char *, const char *); 116 | int mdns_resolve(struct mdns *, const char *, const char *, const char *); 117 | int mdns_open(struct mdns *); 118 | ssize_t mdns_read(struct mdns *); 119 | void mdns_close(struct mdns *); 120 | void mdns_set_browse_hook(struct mdns *, browse_hook); 121 | void mdns_set_resolve_hook(struct mdns *m, resolve_hook); 122 | void mdns_set_lookup_A_hook(struct mdns *, lookup_A_hook); 123 | void mdns_set_lookup_PTR_hook(struct mdns *, lookup_PTR_hook); 124 | void mdns_set_lookup_HINFO_hook(struct mdns *, lookup_HINFO_hook); 125 | void mdns_set_group_hook(struct mdns *, group_hook); 126 | void mdns_set_udata(struct mdns *, void *); 127 | 128 | int mdns_lookup_A(struct mdns *, const char *); 129 | int mdns_lookup_PTR(struct mdns *, const char *); 130 | int mdns_lookup_HINFO(struct mdns *, const char *); 131 | int mdns_lookup_rev(struct mdns *, struct in_addr *); 132 | int mdns_service_init(struct mdns_service *, const char *, const char *, 133 | const char *, u_int16_t, const char *, const char *, struct in_addr *); 134 | int mdns_group_add(struct mdns *, const char *); 135 | int mdns_group_reset(struct mdns *, const char *); 136 | int mdns_group_add_service(struct mdns *, const char *, struct mdns_service *); 137 | int mdns_group_commit(struct mdns *, const char *); 138 | 139 | void reversstr(char [MAXHOSTNAMELEN], struct in_addr *); 140 | 141 | #endif /* _MDNS_H_ */ 142 | -------------------------------------------------------------------------------- /mdnsd/mdnsd.8: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2010, 2011, Christiano F. Haesbaert 3 | .\" 4 | .\" Permission to use, copy, modify, and distribute this software for any 5 | .\" purpose with or without fee is hereby granted, provided that the above 6 | .\" copyright notice and this permission notice appear in all copies. 7 | .\" 8 | .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | .\" 16 | .Dd $Mdocdate: Feb 06 2011 $ 17 | .Dt MDNSD 8 18 | .Os 19 | .Sh NAME 20 | .Nm mdnsd 21 | .Nd Multicast DNS/DNS-SD daemon 22 | .Sh SYNOPSIS 23 | .Nm 24 | .Op Fl dvw 25 | .Ar ifname 26 | .Op Ar ifnames ... 27 | .Sh DESCRIPTION 28 | .Nm 29 | is a Multicast Domain Name System 30 | .Pq mDNS 31 | daemon which acts as the host mDNS querier and responder. 32 | .Nm 33 | supports both raw mDNS as well as DNS-SD (Service Discovery) as described in 34 | the mDNS and DNS-SD RFCs. 35 | .Pp 36 | mDNS is a way to perform DNS-like operations via multicast in the local link, 37 | there is no hierarchy or multiple domains as in conventional unicast DNS. 38 | mDNS provides a way for hosts to co-operate and maintain a cache name database 39 | which can then be used to resolve local host names without the need of a 40 | central DNS server. 41 | .Pp 42 | DNS-SD is a convention on some names used in mDNS to provide hosts with 43 | Service Discovery capabilities. 44 | A host can publish a service of any type, be it a HTTP server, NTP server, a 45 | printer and so on, this services can then be browsed and resolved by the other 46 | hosts in the local network. 47 | .Pp 48 | There are basically two roles in a mDNS environment, the Querier, and the 49 | Responder. 50 | The Querier is the entity responsible for sending questions and mDNS requests 51 | in the local link, it can't be done as it is in libc, where each process does 52 | its own lookup, there must be something centralizing all the requests as there 53 | are various complications implied: cache, timers and so on. 54 | .Pp 55 | The Responder is the entity responsible for answering those queries, there 56 | should be only one responder per host. 57 | Both roles are performed by mDNS. 58 | mDNS operates on the link-local multicast address 224.0.0.251 under UDP 59 | port 5353. 60 | There are no multiple domains in mDNS as in unicast DNS, the .local domain 61 | name is the single mDNS domain name and it's where all the queries and answers 62 | take place. 63 | .Pp 64 | There are three basic types of mDNS question, in which 65 | .Nm 66 | uses two of them. 67 | The One-Shot Query, which resembles unicast DNS, where a single question is 68 | sent and an answer is expected, if no answer is received it means no one can 69 | answer that question. 70 | This question is used for simple lookups. 71 | .Pp 72 | Continuous Multicast Query is a more complex way of querying, the querier will 73 | send the same question multiple times, doubling the interval between each 74 | time, multiple answers may be received, it's used as a way for monitoring the 75 | Resource Records of the network. 76 | This question is mainly used by network browsing in DNS-SD, where a question 77 | for a type of service may enumerate one or more instances, for example, if 78 | browsing for the HTTP servers, there may be one or more servers (instances). 79 | To diminish the volume of redundant answers, a feature called Known Answer 80 | Suppression is present, in which the querier when performing a Continuous 81 | Multicast Query places all the previous known answers in the additional 82 | section of the mDNS packet, thus, any answer that would be given which is 83 | already in the additional section, is suppressed. 84 | .Pp 85 | There are two type of Resource Records, Unique and Shared. 86 | .Pp 87 | Unique records are the ones which there may be only one answer for it in the 88 | local name, the A, PTR and HINFO under the hostname.local name are examples of 89 | Unique records, it would be strange if two hosts would answer an address for 90 | the same foobar.local. 91 | All Unique records must be Probed to verify its uniqueness, if a conflict is 92 | found, another name must be chosen (Unimplemented). 93 | .Pp 94 | A Shared record is used for PTR records in DNS-SD, a host may have as many 95 | answers as necessary for a shared record, it's used only in network browsing, 96 | where there may be multiple instances of the same service. 97 | .Pp 98 | To access the mDNS services, a libmdns library will be provided in the near 99 | future, programs will then, be able to link with libmdns and publish its own 100 | services though mDNS. 101 | By now, only mdnsctl(8) is provided which is a command line interface to the 102 | daemon in the same fashion as ripctl(8) and ospfctl(8). 103 | .Pp 104 | When 105 | .Nm 106 | starts up, it probes for its hostname (fetched from /etc/myname), if there 107 | isn't a conflict, it publishes an A and a PTR record for itself, both records 108 | will be under the .local domain, which is the mDNS single domain name. 109 | All the other domain names in /etc/myname will be stripped, therefore 110 | foo.bar.midearth becomes foo.local, which can be resolved through mDNS. 111 | If a conflict is found, then, there is another foo.local in the network and 112 | conflict resolution takes place. 113 | .Pp 114 | If 115 | Fl w 116 | was not specified, 117 | .Nm 118 | will also publish a Workstation service, this service has no data itself, it's 119 | used to state that the host is up, it can be used for example, to browse every 120 | powered host on the local network. 121 | .Pp 122 | .Nm 123 | supports multiple interfaces, the interfaces used must be specified as the 124 | arguments. 125 | .Pp 126 | .Nm 127 | must be started as root and upon start up it will drop privileges, change it's 128 | euid/egid to _mdnsd and chroot. 129 | Therefore make sure you have user and group _mdnsd created. 130 | .Pp 131 | mDNS operations can be done with the 132 | .Xr mdnsctl 8 133 | utility. 134 | .Pp 135 | The options are as follows: 136 | .Bl -tag -width Ds 137 | .It Fl d 138 | Do not daemonize. 139 | If this option is specified, debugging will be enabled, 140 | .Nm 141 | will run in the foreground and log to 142 | .Em stderr . 143 | .It Fl w 144 | Do not publish a workstation service on startup. 145 | .It Fl v 146 | Print version and exit. 147 | .El 148 | .Sh FILES 149 | .Bl -tag -width "/var/run/mdnsd.sockXX" -compact 150 | .It /var/run/mdnsd.sock 151 | .Ux Ns -domain 152 | socket used for communication with 153 | .Xr mdnsctl 8 . 154 | .El 155 | .Sh SEE ALSO 156 | .Xr mdnsctl 8 157 | .Rs 158 | .%A S. Cheshire 159 | .%A M. Krochmal 160 | .%D February 2013 161 | .%R RFC 6762 162 | .%T Multicast DNS 163 | .Re 164 | .Rs 165 | .%A S. Cheshire 166 | .%A M. Krochmal 167 | .%D February 2013 168 | .%R RFC 6763 169 | .%T DNS-Based Service Discovery 170 | .Re 171 | .Sh LICENSE 172 | .Nm 173 | is released under the ISC license. 174 | .Sh HISTORY 175 | The 176 | .Nm 177 | program version 0.1 was released in 13 February 2011. 178 | .Sh AUTHORS 179 | .An Christiano Farina Haesbaert Aq Mt haesbaert@haesbaert.org 180 | .Sh BUGS 181 | No proper error return in mdnsl.c. 182 | -------------------------------------------------------------------------------- /mdnsd/mdnsd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2014 Christiano F. Haesbaert 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "version.h" 39 | #include "mdnsd.h" 40 | #include "mdns.h" 41 | #include "log.h" 42 | #include "control.h" 43 | 44 | __dead void usage(void); 45 | __dead void display_version(void); 46 | void mdnsd_sig_handler(int, short, void *); 47 | void conf_init_ifaces(int, char *[]); 48 | void mdnsd_shutdown(void); 49 | int mdns_sock(void); 50 | void fetchmyname(char [MAXHOSTNAMELEN]); 51 | void fetchhinfo(struct hinfo *); 52 | struct reflect_rule *parse_reflect_rule(char *); 53 | 54 | struct mdnsd_conf *conf = NULL; 55 | extern char *malloc_options; 56 | 57 | __dead void 58 | usage(void) 59 | { 60 | extern char *__progname; 61 | 62 | fprintf(stderr, "usage: %s [-drw] ifname [ifnames...]\n", 63 | __progname); 64 | fprintf(stderr, "usage: %s -v\n", __progname); 65 | exit(1); 66 | } 67 | 68 | __dead void 69 | display_version(void) 70 | { 71 | printf("OpenMdns Daemon %s\n", MDNS_VERSION); 72 | printf("Copyright (C) 2010-2014 Christiano F. Haesbaert\n"); 73 | 74 | exit(0); 75 | } 76 | 77 | void 78 | conf_init_ifaces(int argc, char *argv[]) 79 | { 80 | int found = 0; 81 | int i; 82 | struct kif *k; 83 | struct iface *iface; 84 | 85 | for (i = 0; i < argc; i++) { 86 | k = kif_findname(argv[i]); 87 | if (k == NULL) { 88 | log_warnx("Unknown interface %s", argv[i]); 89 | continue; 90 | } 91 | 92 | iface = if_new(k); 93 | if (iface == NULL) 94 | continue; 95 | found++; 96 | LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 97 | } 98 | 99 | if (!found) 100 | fatal("Couldn't find any interface"); 101 | 102 | LIST_FOREACH(iface, &conf->iface_list, entry) 103 | log_debug("using iface %s index %u", iface->name, iface->ifindex); 104 | } 105 | 106 | /* ARGSUSED */ 107 | void 108 | mdnsd_sig_handler(int sig, short event, void *arg) 109 | { 110 | /* 111 | * signal handler rules don't apply, libevent decouples for us 112 | */ 113 | 114 | switch (sig) { 115 | case SIGTERM: 116 | case SIGINT: 117 | mdnsd_shutdown(); 118 | break; /* NOTREACHED */ 119 | case SIGHUP: 120 | log_debug("got SIGHUP"); 121 | /* reconfigure */ 122 | /* ... */ 123 | break; 124 | default: 125 | fatalx("unexpected signal"); 126 | /* NOTREACHED */ 127 | } 128 | } 129 | 130 | void 131 | mdnsd_shutdown(void) 132 | { 133 | struct iface *iface; 134 | struct pge *pge; 135 | 136 | /* 137 | * Send goodbye RR for all published records. 138 | */ 139 | while ((pge = TAILQ_FIRST(&pge_queue)) != NULL) 140 | pge_kill(pge); 141 | 142 | while ((iface = LIST_FIRST(&conf->iface_list)) != NULL) { 143 | LIST_REMOVE(iface, entry); 144 | free(iface); 145 | } 146 | 147 | kev_cleanup(); 148 | kif_cleanup(); 149 | control_cleanup(); 150 | free(conf); 151 | 152 | log_info("terminating"); 153 | exit(0); 154 | } 155 | 156 | 157 | int 158 | mdns_sock(void) 159 | { 160 | int sock; 161 | struct sockaddr_in addr; 162 | 163 | if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 164 | fatal("socket"); 165 | 166 | addr.sin_family = AF_INET; 167 | addr.sin_port = htons(MDNS_PORT); 168 | addr.sin_addr.s_addr = INADDR_ANY; 169 | 170 | if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) 171 | fatal("bind"); 172 | 173 | if (if_set_opt(sock) == -1) 174 | fatal("if_set_opt"); 175 | 176 | if (if_set_mcast_ttl(sock, MDNS_TTL) == -1) 177 | fatal("if_set_mcast_ttl"); 178 | 179 | if (if_set_mcast_loop(sock) == -1) 180 | fatal("if_set_mcast_loop"); 181 | 182 | /* if (if_set_tos(sock, IPTOS_PREC_INTERNETCONTROL) == -1) */ 183 | /* fatal("if_set_tos"); */ 184 | 185 | if_set_recvbuf(sock); 186 | 187 | log_debug("mdns sock bound to %s:%u", inet_ntoa(addr.sin_addr), 188 | ntohs(addr.sin_port)); 189 | 190 | return (sock); 191 | } 192 | 193 | void 194 | fetchmyname(char myname[MAXHOSTNAMELEN]) 195 | { 196 | char *end; 197 | 198 | if (gethostname(myname, MAXHOSTNAMELEN) == -1) 199 | fatal("gethostname"); 200 | end = strchr(myname, '.'); 201 | if (end != NULL) 202 | *end = '\0'; /* use short hostnames */ 203 | if (strlcat(myname, ".local", MAXHOSTNAMELEN) >= MAXHOSTNAMELEN) 204 | errx(1, "hostname too long %s", myname); 205 | } 206 | 207 | void 208 | fetchhinfo(struct hinfo *hi) 209 | { 210 | struct utsname utsname; 211 | 212 | if (uname(&utsname) == -1) 213 | fatal("uname"); 214 | bzero(hi, sizeof(*hi)); 215 | strlcpy(hi->cpu, utsname.machine, sizeof(hi->cpu)); 216 | snprintf(hi->os, sizeof(hi->os), "%s %s", utsname.sysname, 217 | utsname.release); 218 | } 219 | 220 | /* 221 | * accept@any:any (should make no sense) 222 | * deny@52:54:00:0e:a3:0e:any 223 | * accept@any:_http._tcp 224 | * deny@192.168.1.1:_http._tcp 225 | * accept@192.168.1.1:any 226 | */ 227 | struct reflect_rule * 228 | parse_reflect_rule(char *s) 229 | { 230 | char *p, *host, *sname, *last = NULL; 231 | struct in_addr ip4; 232 | struct ether_addr *mac; 233 | struct reflect_rule *rule; 234 | int htype, accept; 235 | 236 | /* Get the policy */ 237 | p = strchr(p, '@'); 238 | if (p == NULL) 239 | return (NULL); 240 | *p++ = 0; 241 | /* Save where host begins */ 242 | host = p; 243 | if (!strcmp(s, "accept")) 244 | accept = 1; 245 | else if (!strcmp(s, "deny")) 246 | accept = 0; 247 | else 248 | return (NULL); 249 | 250 | /* Find the last : */ 251 | while ((p = strchr(p, ':')) != NULL) 252 | last = p++; 253 | 254 | /* Break it; */ 255 | *last++ = 0; 256 | sname = last; 257 | last = NULL; 258 | 259 | /* Mac, ip4 or any ? */ 260 | if (inet_aton(host, &ip4) == 1) 261 | htype = REFLECT_HTYPE_IP4; 262 | else if ((mac = (ether_aton(host))) != NULL) 263 | htype = REFLECT_HTYPE_MAC; 264 | else if (!strcmp(host, "any")) 265 | htype = REFLECT_HTYPE_ANY; 266 | else 267 | return (NULL); 268 | 269 | if ((rule = calloc(1, sizeof(*rule))) == NULL) 270 | fatal("calloc"); 271 | if (snprintf(rule->sname, sizeof(rule->sname), "%s.local", sname) 272 | >= MAXHOSTNAMELEN) 273 | return (NULL); 274 | switch (htype) { 275 | case REFLECT_HTYPE_ANY: 276 | /* nada */ 277 | break; 278 | case REFLECT_HTYPE_MAC: 279 | memcpy(&rule->u.mac, mac, sizeof(rule->u.mac)); 280 | break; 281 | case REFLECT_HTYPE_IP4: 282 | rule->u.ip4.s_addr = ip4.s_addr; 283 | break; 284 | default: 285 | fatal("invalid htype"); 286 | } 287 | 288 | return (rule); 289 | } 290 | 291 | int 292 | main(int argc, char *argv[]) 293 | { 294 | int ch; 295 | int debug, no_workstation; 296 | struct passwd *pw; 297 | struct iface *iface; 298 | struct event ev_sigint, ev_sigterm, ev_sighup; 299 | struct reflect_rule *rule; 300 | struct reflect_rules reflect_rules; 301 | 302 | debug = no_workstation = 0; 303 | TAILQ_INIT(&reflect_rules); 304 | 305 | /* Make sure we set malloc_options before any possible malloc */ 306 | while ((ch = getopt(argc, argv, "dvwr:")) != -1) { 307 | switch (ch) { 308 | case 'd': 309 | debug = 1; 310 | malloc_options = "CFGJ"; 311 | break; 312 | default: 313 | break; 314 | } 315 | } 316 | 317 | optreset = 1; 318 | 319 | while ((ch = getopt(argc, argv, "dvwr:")) != -1) { 320 | switch (ch) { 321 | case 'd': /* Already handled */ 322 | break; 323 | case 'r': 324 | if ((rule = parse_reflect_rule(optarg)) == NULL) 325 | usage(); 326 | TAILQ_INSERT_TAIL(&reflect_rules, rule, entry); 327 | break; 328 | case 'v': 329 | display_version(); 330 | break; /* NOTREACHED */ 331 | case 'w': 332 | no_workstation = 1; 333 | break; 334 | default: 335 | usage(); 336 | /* NOTREACHED */ 337 | } 338 | } 339 | 340 | log_init(1); /* log to stderr until daemonized */ 341 | 342 | argc -= optind; 343 | argv += optind; 344 | 345 | if (!argc) 346 | usage(); 347 | 348 | /* check for root privileges */ 349 | if (geteuid()) 350 | errx(1, "need root privileges"); 351 | 352 | /* check for mdnsd user */ 353 | if ((pw = getpwnam(MDNSD_USER)) == NULL) 354 | fatal("getpwnam, make sure you have user and group _mdnsd"); 355 | 356 | log_init(debug); 357 | 358 | if (!debug) 359 | daemon(1, 0); 360 | 361 | log_info("startup"); 362 | 363 | /* init control before chroot */ 364 | if (control_init() == -1) 365 | fatalx("control socket setup failed"); 366 | 367 | /* chroot */ 368 | if (chroot(pw->pw_dir) == -1) 369 | fatal("chroot"); 370 | if (chdir("/") == -1) 371 | fatal("chdir(\"/\")"); 372 | 373 | /* show who we are */ 374 | setproctitle("mdnsd"); 375 | 376 | /* drop privileges */ 377 | if (setgroups(1, &pw->pw_gid) || 378 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 379 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 380 | fatal("error droping privileges"); 381 | 382 | /* init libevent */ 383 | event_init(); 384 | 385 | /* setup signals */ 386 | signal_set(&ev_sigint, SIGINT, mdnsd_sig_handler, NULL); 387 | signal_set(&ev_sigterm, SIGTERM, mdnsd_sig_handler, NULL); 388 | signal_set(&ev_sighup, SIGHUP, mdnsd_sig_handler, NULL); 389 | signal_add(&ev_sigint, NULL); 390 | signal_add(&ev_sigterm, NULL); 391 | signal_add(&ev_sighup, NULL); 392 | signal(SIGPIPE, SIG_IGN); 393 | 394 | /* fetch all kernel interfaces */ 395 | if (kif_init() != 0) 396 | fatal("Can't get kernel interfaces"); 397 | 398 | /* init conf */ 399 | if ((conf = calloc(1, sizeof(*conf))) == NULL) 400 | fatal("calloc"); 401 | fetchmyname(conf->myname); 402 | fetchhinfo(&conf->hi); 403 | LIST_INIT(&conf->iface_list); 404 | conf->no_workstation = no_workstation; 405 | conf->reflect_rules = reflect_rules; 406 | 407 | /* init RR cache */ 408 | cache_init(); 409 | 410 | /* init publish queues */ 411 | pg_init(); 412 | 413 | /* init interfaces and names */ 414 | conf_init_ifaces(argc, argv); 415 | 416 | /* Create primary pge */ 417 | pge_initprimary(); 418 | 419 | /* init some packet internals */ 420 | packet_init(); 421 | 422 | /* init querier */ 423 | query_init(); 424 | 425 | /* listen to kernel interface events */ 426 | kev_init(); 427 | 428 | /* create mdns socket */ 429 | conf->mdns_sock = mdns_sock(); 430 | 431 | /* setup mdns events */ 432 | event_set(&conf->ev_mdns, conf->mdns_sock, EV_READ|EV_PERSIST, 433 | recv_packet, NULL); 434 | event_add(&conf->ev_mdns, NULL); 435 | 436 | /* start interfaces */ 437 | LIST_FOREACH(iface, &conf->iface_list, entry) { 438 | /* XXX yep it seems wrong indeed */ 439 | iface->fd = conf->mdns_sock; 440 | if (if_fsm(iface, IF_EVT_UP)) 441 | log_warnx("error starting interface %s", iface->name); 442 | } 443 | 444 | /* listen on mdns control socket */ 445 | TAILQ_INIT(&ctl_conns); 446 | control_listen(); 447 | 448 | /* parent mainloop */ 449 | event_dispatch(); 450 | 451 | return (0); 452 | } 453 | 454 | void 455 | imsg_event_add(struct imsgev *iev) 456 | { 457 | if (iev->handler == NULL) { 458 | imsg_flush(&iev->ibuf); 459 | return; 460 | } 461 | 462 | iev->events = EV_READ; 463 | if (iev->ibuf.w.queued) 464 | iev->events |= EV_WRITE; 465 | 466 | event_del(&iev->ev); 467 | event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 468 | event_add(&iev->ev, NULL); 469 | } 470 | 471 | int 472 | mdnsd_imsg_compose_ctl(struct ctl_conn *c, u_int16_t type, 473 | void *data, u_int16_t datalen) 474 | { 475 | return (imsg_compose_event(&c->iev, type, 0, 0, -1, data, datalen)); 476 | } 477 | 478 | int 479 | imsg_compose_event(struct imsgev *iev, u_int16_t type, 480 | u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen) 481 | { 482 | int ret; 483 | 484 | if ((ret = imsg_compose(&iev->ibuf, type, peerid, 485 | pid, fd, data, datalen)) != -1) 486 | imsg_event_add(iev); 487 | return (ret); 488 | } 489 | 490 | int 491 | peersuser(int fd) 492 | { 493 | uid_t euid; 494 | 495 | if (getpeereid(fd, &euid, NULL) == -1) 496 | fatal("getpeereid"); 497 | return (euid == 0); 498 | } 499 | -------------------------------------------------------------------------------- /mdnsd/mdnsd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Christiano F. Haesbaert 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _MDNSD_H_ 18 | #define _MDNSD_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include "mdns.h" 34 | #include "control.h" 35 | 36 | #define MDNSD_USER "_mdnsd" 37 | #define ALL_MDNS_DEVICES "224.0.0.251" 38 | #define MDNS_TTL 255 39 | #define MDNS_PORT 5353 40 | #define TTL_A 120 41 | #define TTL_AAAA 120 42 | #define TTL_HNAME 120 43 | #define TTL_SRV (75 * 60) 44 | #define TTL_TXT (75 * 60) 45 | #define TTL_PTR (75 * 60) 46 | #define MDNS_QUERY 0 47 | #define MDNS_RESPONSE 1 48 | #define INTERVAL_PROBETIME 250000 49 | #define RANDOM_PROBETIME arc4random_uniform(250000) 50 | #define FIRST_QUERYTIME (arc4random_uniform(120000) + 20000) 51 | #define MAXQUERYTIME (60 * 60) /* one hour */ 52 | #define ALL_IFACE (NULL) 53 | 54 | #define ANSWERS(qrrs, rrs) \ 55 | ((((qrrs)->type == T_ANY) || ((qrrs)->type == (rrs)->type)) && \ 56 | (qrrs)->class == (rrs)->class && \ 57 | (strcmp((qrrs)->dname, (rrs)->dname)) == 0) 58 | 59 | #define RR_UNIQ(rr) ((rr)->flags & RR_FLAG_CACHEFLUSH) 60 | #define RR_AUTH(rr) ((rr)->auth_refcount > 0) 61 | #define RR_INADDRANY(rr) \ 62 | ((rr)->rrs.type == T_A && (rr)->rdata.A.s_addr == INADDR_ANY) 63 | 64 | #define CACHE_FOREACH_RRS(var, rrs) \ 65 | /* struct rr *var */ \ 66 | /* struct rrs *rrs */ \ 67 | for ((var) = cache_lookup(rrs); \ 68 | (var) != NULL; \ 69 | (var) = cache_next_by_rrs(var)) 70 | 71 | #define CACHE_FOREACH_DNAME(var, var2, dname) \ 72 | /* struct rr *var */ \ 73 | /* struct cache_node *var2 */ \ 74 | /* char dname[MAXHOSTNAMELEN] */ \ 75 | for (((var2) = cache_lookup_dname(dname)), \ 76 | (var2) ? \ 77 | ((var) = LIST_FIRST(&(var2)->rr_list)) : NULL ; \ 78 | (var2) != NULL && (var) != NULL; \ 79 | (var) = LIST_NEXT(var, centry)) \ 80 | 81 | struct rrset { 82 | LIST_ENTRY(rrset) entry; /* List link */ 83 | char dname[MAXHOSTNAMELEN]; /* Domain Name */ 84 | u_int16_t type; /* RR type: T_A, T_PTR... */ 85 | u_int16_t class; /* C_IN */ 86 | }; 87 | 88 | struct cache_node { 89 | RB_ENTRY(cache_node) entry; /* Cache RBTREE link */ 90 | LIST_HEAD(, rr) rr_list; /* List of RR under dname */ 91 | char dname[MAXHOSTNAMELEN]; /* domain name */ 92 | }; 93 | 94 | struct hinfo { 95 | char cpu[MAXCHARSTR]; /* Cpu name */ 96 | char os[MAXCHARSTR]; /* Operating System name */ 97 | }; 98 | 99 | struct srv { 100 | u_int16_t priority; /* Used only by application */ 101 | u_int16_t weight; /* Used only by application */ 102 | u_int16_t port; /* Service port, tcp or udp */ 103 | char target[MAXHOSTNAMELEN]; /* Service host */ 104 | }; 105 | 106 | struct rr { 107 | LIST_ENTRY(rr) centry; /* Cache entry */ 108 | LIST_ENTRY(rr) pentry; /* Packet entry */ 109 | struct rrset rrs; /* RR tripple */ 110 | u_int32_t ttl; /* DNS Time to live */ 111 | union { 112 | /* IPv4 Address, if INADDR_ANY, use the interface address, this 113 | * is how we can have the same RR with multiple addresses */ 114 | struct in_addr A; 115 | char CNAME[MAXHOSTNAMELEN]; /* CNAME */ 116 | char PTR[MAXHOSTNAMELEN]; /* PTR */ 117 | char NS[MAXHOSTNAMELEN]; /* Name server */ 118 | char TXT[MAXCHARSTR]; /* Text */ 119 | struct srv SRV; /* Service */ 120 | struct hinfo HINFO; /* Host Info */ 121 | 122 | } rdata; 123 | struct cache_node *cn; /* Cache parent node */ 124 | int auth_refcount; /* Number of pges holding us */ 125 | int revision; /* at 80% of ttl, then 90% and 95% */ 126 | struct event timer; /* revision timer */ 127 | struct timespec age; /* Timestamp of when we got this RR. */ 128 | u_int flags; /* RR Flags */ 129 | #define RR_FLAG_CACHEFLUSH 0x01 /* Unique record */ 130 | #define RR_FLAG_PUBLISHED 0x02 /* Published record */ 131 | }; 132 | 133 | struct pkt { 134 | TAILQ_ENTRY(pkt) entry; /* Deferred pkt queue */ 135 | u_int flags; /* Packet flags */ 136 | #define PKT_FLAG_LEGACY 0x1 /* Legacy unicast packet */ 137 | HEADER h; /* Packet header */ 138 | LIST_HEAD(, question) qlist; /* Question section */ 139 | LIST_HEAD(, rr) anlist; /* Answer section */ 140 | LIST_HEAD(, rr) nslist; /* Authority section */ 141 | LIST_HEAD(, rr) arlist; /* Additional section */ 142 | struct sockaddr_in ipsrc; /* Received ipsource */ 143 | struct event timer; /* Timer for truncated pkts */ 144 | struct iface *iface; /* Received interface */ 145 | }; 146 | 147 | struct question { 148 | LIST_ENTRY(question) entry; /* Packet link */ 149 | RB_ENTRY(question) qst_entry; /* Question Tree link */ 150 | struct rrset rrs; /* RR tripple */ 151 | u_int flags; /* Question flags */ 152 | #define QST_FLAG_UNIRESP 0x1 /* Accepts unicast response */ 153 | int active; /* Active controllers */ 154 | u_int sent; /* Used in question_fsm */ 155 | struct timespec lastsent; /* Last time we sent this question */ 156 | struct timespec sched; /* Next scheduled time to send */ 157 | }; 158 | 159 | enum query_style { 160 | QUERY_LOOKUP, /* A simple single-shot query */ 161 | QUERY_BROWSE, /* A Continuous Querying query */ 162 | QUERY_RESOLVE, /* A service resolve query */ 163 | }; 164 | 165 | struct query { 166 | LIST_ENTRY(query) entry; /* Query link */ 167 | LIST_HEAD(, rrset) rrslist;/* List of question tree keys */ 168 | struct ctl_conn *ctl; /* Owner */ 169 | enum query_style style; /* Style */ 170 | struct event timer; /* query_fsm() timer */ 171 | u_int count; /* Used in query_fsm() */ 172 | struct rrset *ms_srv; /* The SRV in QUERY_RESOLVE */ 173 | struct rrset *ms_a; /* The A in QUERY_RESOLVE */ 174 | struct rrset *br_ptr; /* The PTR in QUERY_BROWSE */ 175 | }; 176 | 177 | enum pg_state { 178 | PG_STA_NEW, 179 | PG_STA_COMMITED, 180 | PG_STA_COLLISION 181 | }; 182 | /* Publish Group */ 183 | struct pg { 184 | TAILQ_ENTRY(pg) entry; /* pg_queue link */ 185 | LIST_HEAD(, pge) pge_list; /* List of pge */ 186 | struct ctl_conn *c; /* Owner */ 187 | char name[MAXHOSTNAMELEN]; /* Name id */ 188 | u_int flags; /* Misc flags */ 189 | enum pg_state state; /* enum pg_state */ 190 | }; 191 | 192 | /* Publish Group Entry types */ 193 | enum pge_type { 194 | PGE_TYPE_CUSTOM, /* Unused */ 195 | PGE_TYPE_SERVICE, /* A DNS-SD Service */ 196 | PGE_TYPE_ADDRESS /* A Primary Address */ 197 | }; 198 | 199 | enum pge_state { 200 | PGE_STA_UNPUBLISHED, /* Initial state */ 201 | PGE_STA_PROBING, /* Probing state */ 202 | PGE_STA_ANNOUNCING, /* Considered announced */ 203 | PGE_STA_PUBLISHED, /* Finished announcing */ 204 | }; 205 | 206 | #define PGE_RR_MAX 32 207 | struct pge { 208 | TAILQ_ENTRY(pge) entry; /* pge_queue link */ 209 | LIST_ENTRY(pge) pge_entry; /* Group link */ 210 | struct pg *pg; /* Parent Publish Group */ 211 | enum pge_type pge_type; /* Type of this entry */ 212 | u_int pge_flags; /* Misc flags */ 213 | #define PGE_FLAG_INC_A 0x01 /* Include primary T_A record */ 214 | #define PGE_FLAG_INTERNAL 0x02 /* TODO: kill and test for pg */ 215 | struct question *pqst; /* Probing Question, may be NULL */ 216 | struct rr *rr[PGE_RR_MAX]; /* Array of to publish rr */ 217 | #define PGE_RR_PRIM 0 /* The T_A record for primary address */ 218 | int nrr; /* Members in rr array */ 219 | struct iface *iface; /* Iface to be published */ 220 | struct event timer; /* FSM timer */ 221 | enum pge_state state; /* FSM state */ 222 | u_int sent; /* How many sent packets */ 223 | }; 224 | 225 | /* Publish Group Queue, should hold all publishing groups */ 226 | TAILQ_HEAD(, pg) pg_queue; 227 | /* Publish Group Entry Queue, should hold all publishing group entries */ 228 | TAILQ_HEAD(, pge) pge_queue; 229 | 230 | struct kif { 231 | char ifname[IF_NAMESIZE]; 232 | u_int64_t baudrate; 233 | int flags; 234 | int mtu; 235 | u_short ifindex; 236 | u_int8_t media_type; 237 | u_int8_t link_state; 238 | struct ether_addr ea; 239 | }; 240 | 241 | /* interface states */ 242 | #define IF_STA_DOWN 0x01 243 | #define IF_STA_ACTIVE (~IF_STA_DOWN) 244 | #define IF_STA_ANY 0x7f 245 | 246 | /* interface events */ 247 | enum iface_event { 248 | IF_EVT_NOTHING, 249 | IF_EVT_UP, 250 | IF_EVT_DOWN 251 | }; 252 | 253 | /* interface actions */ 254 | enum iface_action { 255 | IF_ACT_NOTHING, 256 | IF_ACT_STRT, 257 | IF_ACT_RST 258 | }; 259 | 260 | /* interface types */ 261 | enum iface_type { 262 | IF_TYPE_POINTOPOINT, 263 | IF_TYPE_BROADCAST, 264 | IF_TYPE_NBMA, 265 | IF_TYPE_POINTOMULTIPOINT 266 | }; 267 | 268 | struct iface { 269 | LIST_ENTRY(iface) entry; 270 | struct pge *pge_workstation; 271 | char name[IF_NAMESIZE]; 272 | struct in_addr addr; 273 | struct in_addr dst; 274 | struct in_addr mask; 275 | u_int64_t baudrate; 276 | time_t uptime; 277 | u_int mtu; 278 | int fd; /* XXX */ 279 | int state; 280 | u_short ifindex; 281 | u_int16_t cost; 282 | u_int16_t flags; 283 | enum iface_type type; 284 | u_int8_t linktype; 285 | u_int8_t media_type; 286 | u_int8_t linkstate; 287 | struct ether_addr ea; 288 | }; 289 | 290 | /* interface.c */ 291 | const char *if_action_name(int); 292 | const char *if_event_name(int); 293 | int if_act_reset(struct iface *); 294 | int if_act_start(struct iface *); 295 | int if_fsm(struct iface *, enum iface_event); 296 | int if_join_group(struct iface *, struct in_addr *); 297 | int if_leave_group(struct iface *, struct in_addr *); 298 | int if_set_mcast(struct iface *); 299 | int if_set_mcast_loop(int); 300 | int if_set_mcast_ttl(int, u_int8_t); 301 | int if_set_opt(int); 302 | int if_set_tos(int, int); 303 | struct iface *if_find_index(u_short); 304 | struct iface *if_find_iface(unsigned int, struct in_addr); 305 | struct iface *if_new(struct kif *); 306 | void if_set_recvbuf(int); 307 | 308 | /* Host type is any (wildcard), an ipv4 or a mac address */ 309 | enum reflect_rule_htype { 310 | REFLECT_HTYPE_ANY, 311 | REFLECT_HTYPE_IP4, 312 | REFLECT_HTYPE_MAC 313 | }; 314 | 315 | TAILQ_HEAD(reflect_rules, reflect_rule); 316 | 317 | struct reflect_rule { 318 | TAILQ_ENTRY(reflect_rule) entry; 319 | char sname[MAXHOSTNAMELEN]; /* as _http._tcp, or any */ 320 | enum reflect_rule_htype htype; /* match host ? */ 321 | int accept; /* deny if !accept */ 322 | union { 323 | struct ether_addr mac; /* mac address if HTYPE_MAC */ 324 | struct in_addr ip4; /* ipv4 if HTYPE_IP4 */ 325 | } u; 326 | }; 327 | 328 | struct mdnsd_conf { 329 | LIST_HEAD(, iface) iface_list; /* Our interface list */ 330 | int mdns_sock; /* MDNS socket bound to udp 5353 */ 331 | struct event ev_mdns; /* MDNS socket event */ 332 | struct hinfo hi; /* MDNS Host Info */ 333 | char myname[MAXHOSTNAMELEN]; /* Hostname */ 334 | struct pge *pge_primary;/* Primary pge addresses */ 335 | int no_workstation; /* Don't publish workstation */ 336 | struct reflect_rules reflect_rules; 337 | /* TAILQ_HEAD(, reflect_rule) reflect_rules; /\* What should we reflect *\/ */ 338 | }; 339 | 340 | /* kiface.c */ 341 | int kif_init(void); 342 | void kif_cleanup(void); 343 | struct kif *kif_findname(char *); 344 | void kev_init(void); 345 | void kev_cleanup(void); 346 | 347 | /* mdnsd.c */ 348 | int peersuser(int); 349 | void reversstr(char [MAXHOSTNAMELEN], struct in_addr *); 350 | int mdnsd_imsg_compose_ctl(struct ctl_conn *, u_int16_t, void *, u_int16_t); 351 | void imsg_event_add(struct imsgev *); 352 | int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t, pid_t, 353 | int, void *, u_int16_t); 354 | 355 | /* packet.c */ 356 | void packet_init(void); 357 | void recv_packet(int, short, void *); 358 | int send_packet(struct iface *, void *, size_t, struct sockaddr_in *); 359 | void pkt_process(int, short, void *); 360 | struct pkt *pkt_reflect_filter(struct pkt *); 361 | void pkt_reflect(struct pkt *); 362 | int pkt_sendto(struct pkt *, struct iface *, struct sockaddr_in *); 363 | int pkt_send(struct pkt *, struct iface *); 364 | void pkt_init(struct pkt *); 365 | struct pkt *pkt_dup(struct pkt *); 366 | void pkt_cleanup(struct pkt *); 367 | void pkt_free(struct pkt *); 368 | void pkt_add_question(struct pkt *, struct question *); 369 | void pkt_add_anrr(struct pkt *, struct rr *); 370 | void pkt_remove_anrr(struct pkt *, struct rr *); 371 | void pkt_add_nsrr(struct pkt *, struct rr *); 372 | void pkt_add_arrr(struct pkt *, struct rr *); 373 | void pkt_remove_arrr(struct pkt *, struct rr *); 374 | int rr_rdata_cmp(struct rr *, struct rr *); 375 | u_int32_t rr_ttl_left(struct rr *); 376 | void pktcomp_reset(int, u_int8_t *, u_int16_t); 377 | int rr_set(struct rr *, char [MAXHOSTNAMELEN], u_int16_t, u_int16_t, 378 | u_int32_t, u_int, void *, size_t); 379 | 380 | /* mdns.c */ 381 | void publish_init(void); 382 | void publish_allrr(struct iface *); 383 | int publish_insert(struct iface *, struct rr *); 384 | int publish_delete(struct iface *, struct rr *); 385 | struct rr *publish_lookupall(struct rrset *); 386 | void publish_fsm(int, short, void *); 387 | void query_init(void); 388 | void query_fsm(int, short, void *); 389 | struct query *query_lookup(struct rrset *); 390 | void query_remove(struct query *); 391 | struct question *question_add(struct rrset *); 392 | void question_remove(struct rrset *); 393 | void cache_init(void); 394 | int cache_insert(struct rr *); 395 | int cache_delete(struct rr *); 396 | void cache_schedrev(struct rr *); 397 | void cache_rev(int, short, void *); 398 | int cache_node_cmp(struct cache_node *, struct cache_node *); 399 | int cache_process(struct rr *); 400 | struct rr *cache_lookup(struct rrset *); 401 | struct cache_node *cache_lookup_dname(const char *); 402 | struct rr *cache_next_by_rrs(struct rr *); 403 | int rrset_cmp(struct rrset *, struct rrset *); 404 | int rr_notify_in(struct rr *); 405 | int rr_notify_out(struct rr *); 406 | struct rr *rr_dup(struct rr *); 407 | struct question *question_dup(struct question *); 408 | void pg_init(void); 409 | void pg_publish_byiface(struct iface *); 410 | struct pg *pg_get(int, char [MAXHOSTNAMELEN], struct ctl_conn *); 411 | void pg_kill(struct pg *); 412 | int pg_published(struct pg *); 413 | struct pge *pge_from_ms(struct pg *, struct mdns_service *, struct iface *); 414 | void pge_kill(struct pge *); 415 | void pge_fsm(int, short, void *); 416 | void pge_fsm_restart(struct pge *, struct timeval *); 417 | void pge_initprimary(void); 418 | struct pge *pge_new_workstation(struct iface *); 419 | void pge_revert_probe(struct pge *); 420 | void pge_conflict_drop(struct pge *); 421 | struct rr * auth_get(struct rr *); 422 | void auth_release(struct rr *); 423 | int rr_send_goodbye(struct rr *); 424 | int rr_send_an(struct rr *); 425 | void conflict_resolve_by_rr(struct rr *); 426 | 427 | /* control.c */ 428 | TAILQ_HEAD(ctl_conns, ctl_conn) ctl_conns; 429 | int control_send_rr(struct ctl_conn *, struct rr *, int); 430 | int control_send_ms(struct ctl_conn *, struct mdns_service *, int); 431 | int control_try_answer_ms(struct ctl_conn *, char[MAXHOSTNAMELEN]); 432 | int control_notify_pg(struct ctl_conn *, struct pg *, int); 433 | 434 | 435 | #endif /* _MDNSD_H_ */ 436 | -------------------------------------------------------------------------------- /mkbuild: -------------------------------------------------------------------------------- 1 | #!/bin/ksh 2 | 3 | set -x 4 | 5 | cd /home/haesbaert/src/mdnsd 6 | make clean 7 | version=$(grep '#define MDNS_VERSION ' version.h | \ 8 | sed 's/#define MDNS_VERSION //' | \ 9 | sed 's/\"//g' | 10 | cut -d ' ' -f 1) 11 | cat < /tmp/distfiles 12 | mdnsd/mdnsd 13 | mdnsd/mdnsctl 14 | mdnsd/TODO 15 | mdnsd/README 16 | mdnsd/Makefile 17 | mdnsd/version.h 18 | EOF 19 | 20 | tar -s "/mdns\//openmdns-$version\//g" \ 21 | -C ../ -czvf openmdns-$version.tar.gz -I /tmp/distfiles 22 | 23 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Christiano F. Haesbaert 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _MDNS_VERSION_H 18 | #define _MDNS_VERSION_H 19 | 20 | #ifndef MDNS_VERSION 21 | #define MDNS_VERSION "0.7 (2017-03-10)" 22 | #endif /* MDNS_VERSION */ 23 | 24 | #endif /* _MDNS_VERSION_H */ 25 | --------------------------------------------------------------------------------