1 /***
2   This file is part of avahi.
3 
4   avahi is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2.1 of the
7   License, or (at your option) any later version.
8 
9   avahi is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12   Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with avahi; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <sys/types.h>
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <arpa/inet.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <stdio.h>
31 
32 #include "address.h"
33 #include "avahi-malloc.h"
34 
address_get_size(const AvahiAddress * a)35 static size_t address_get_size(const AvahiAddress *a) {
36     assert(a);
37 
38     if (a->proto == AVAHI_PROTO_INET)
39         return 4;
40     else if (a->proto == AVAHI_PROTO_INET6)
41         return 16;
42 
43     return 0;
44 }
45 
avahi_address_cmp(const AvahiAddress * a,const AvahiAddress * b)46 int avahi_address_cmp(const AvahiAddress *a, const AvahiAddress *b) {
47     assert(a);
48     assert(b);
49 
50     if (a->proto != b->proto)
51         return -1;
52 
53     return memcmp(a->data.data, b->data.data, address_get_size(a));
54 }
55 
avahi_address_snprint(char * s,size_t length,const AvahiAddress * a)56 char *avahi_address_snprint(char *s, size_t length, const AvahiAddress *a) {
57     assert(s);
58     assert(length);
59     assert(a);
60 
61     if (!(inet_ntop(avahi_proto_to_af(a->proto), a->data.data, s, length)))
62         return NULL;
63 
64     return s;
65 }
66 
avahi_reverse_lookup_name(const AvahiAddress * a,char * ret_s,size_t length)67 char* avahi_reverse_lookup_name(const AvahiAddress *a, char *ret_s, size_t length) {
68     assert(ret_s);
69     assert(length > 0);
70     assert(a);
71 
72     if (a->proto == AVAHI_PROTO_INET) {
73         uint32_t n = ntohl(a->data.ipv4.address);
74         snprintf(
75             ret_s, length,
76             "%u.%u.%u.%u.in-addr.arpa",
77             n & 0xFF, (n >> 8) & 0xFF, (n >> 16) & 0xFF, n >> 24);
78     } else {
79         assert(a->proto == AVAHI_PROTO_INET6);
80 
81         snprintf(
82             ret_s, length,
83             "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
84             a->data.ipv6.address[15] & 0xF, a->data.ipv6.address[15] >> 4,
85             a->data.ipv6.address[14] & 0xF, a->data.ipv6.address[14] >> 4,
86             a->data.ipv6.address[13] & 0xF, a->data.ipv6.address[13] >> 4,
87             a->data.ipv6.address[12] & 0xF, a->data.ipv6.address[12] >> 4,
88             a->data.ipv6.address[11] & 0xF, a->data.ipv6.address[11] >> 4,
89             a->data.ipv6.address[10] & 0xF, a->data.ipv6.address[10] >> 4,
90             a->data.ipv6.address[ 9] & 0xF, a->data.ipv6.address[ 9] >> 4,
91             a->data.ipv6.address[ 8] & 0xF, a->data.ipv6.address[ 8] >> 4,
92             a->data.ipv6.address[ 7] & 0xF, a->data.ipv6.address[ 7] >> 4,
93             a->data.ipv6.address[ 6] & 0xF, a->data.ipv6.address[ 6] >> 4,
94             a->data.ipv6.address[ 5] & 0xF, a->data.ipv6.address[ 5] >> 4,
95             a->data.ipv6.address[ 4] & 0xF, a->data.ipv6.address[ 4] >> 4,
96             a->data.ipv6.address[ 3] & 0xF, a->data.ipv6.address[ 3] >> 4,
97             a->data.ipv6.address[ 2] & 0xF, a->data.ipv6.address[ 2] >> 4,
98             a->data.ipv6.address[ 1] & 0xF, a->data.ipv6.address[ 1] >> 4,
99             a->data.ipv6.address[ 0] & 0xF, a->data.ipv6.address[ 0] >> 4);
100     }
101 
102     return ret_s;
103 }
104 
avahi_address_parse(const char * s,AvahiProtocol proto,AvahiAddress * ret_addr)105 AvahiAddress *avahi_address_parse(const char *s, AvahiProtocol proto, AvahiAddress *ret_addr) {
106     assert(ret_addr);
107     assert(s);
108 
109     if (proto == AVAHI_PROTO_UNSPEC) {
110         if (inet_pton(AF_INET, s, ret_addr->data.data) <= 0) {
111             if (inet_pton(AF_INET6, s, ret_addr->data.data) <= 0)
112                 return NULL;
113             else
114                 ret_addr->proto = AVAHI_PROTO_INET6;
115         } else
116             ret_addr->proto = AVAHI_PROTO_INET;
117     } else {
118         if (inet_pton(avahi_proto_to_af(proto), s, ret_addr->data.data) <= 0)
119             return NULL;
120 
121         ret_addr->proto = proto;
122     }
123 
124     return ret_addr;
125 }
126 
avahi_proto_to_af(AvahiProtocol proto)127 int avahi_proto_to_af(AvahiProtocol proto) {
128     if (proto == AVAHI_PROTO_INET)
129         return AF_INET;
130     if (proto == AVAHI_PROTO_INET6)
131         return AF_INET6;
132 
133     assert(proto == AVAHI_PROTO_UNSPEC);
134     return AF_UNSPEC;
135 }
136 
avahi_af_to_proto(int af)137 AvahiProtocol avahi_af_to_proto(int af) {
138     if (af == AF_INET)
139         return AVAHI_PROTO_INET;
140     if (af == AF_INET6)
141         return AVAHI_PROTO_INET6;
142 
143     assert(af == AF_UNSPEC);
144     return AVAHI_PROTO_UNSPEC;
145 }
146 
avahi_proto_to_string(AvahiProtocol proto)147 const char* avahi_proto_to_string(AvahiProtocol proto) {
148     if (proto == AVAHI_PROTO_INET)
149         return "IPv4";
150     if (proto == AVAHI_PROTO_INET6)
151         return "IPv6";
152 
153     assert(proto == AVAHI_PROTO_UNSPEC);
154     return "UNSPEC";
155 }
156