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
35static 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
46int 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
56char *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
67char* 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
105AvahiAddress *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
127int 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
137AvahiProtocol 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
147const 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