]> git.tdb.fi Git - netvis.git/blob - source/address.cpp
Support IPv6
[netvis.git] / source / address.cpp
1 #include <algorithm>
2 #include <stdexcept>
3 #include <arpa/inet.h>
4 #include <netinet/ether.h>
5 #include "address.h"
6
7 using namespace std;
8
9 Address::Address():
10         type(0),
11         length(0),
12         mask_bits(0)
13 { }
14
15 Address::Address(uint32_t a):
16         type(ETH_P_IP),
17         length(4),
18         mask_bits(32)
19 {
20         for(unsigned i=0; i<4; ++i)
21                 data[i] = a>>(24-i*8);
22 }
23
24 Address::Address(const in6_addr &a):
25         type(ETH_P_IPV6),
26         length(16),
27         mask_bits(128)
28 {
29         copy(a.s6_addr, a.s6_addr+16, data);
30 }
31
32 Address::Address(unsigned short t, const unsigned char *d, unsigned char l):
33         type(t),
34         length(l)
35 {
36         copy(d, d+l, data);
37 }
38
39 void Address::set_mask(const Address &mask)
40 {
41         if(mask.length!=length)
42                 throw invalid_argument("Address::set_mask");
43
44         mask_bits = 0;
45         for(unsigned i=0; (i<length && mask.data[i]); ++i)
46         {
47                 mask_bits += 8;
48                 if(mask.data[i]!=0xFF)
49                 {
50                         for(unsigned d=mask.data[i]; !(d&1); d>>=1)
51                                 --mask_bits;
52                         break;
53                 }
54         }
55 }
56
57 string Address::str() const
58 {
59         if(type==ETH_P_IP)
60         {
61                 char buf[INET_ADDRSTRLEN];
62                 return inet_ntop(AF_INET, data, buf, INET_ADDRSTRLEN);
63         }
64         else if(type==ETH_P_IPV6)
65         {
66                 char buf[INET6_ADDRSTRLEN];
67                 return inet_ntop(AF_INET6, data, buf, INET6_ADDRSTRLEN);
68         }
69         else
70                 return "<unknown>";
71 }
72
73 unsigned Address::common_prefix_length(const Address &other) const
74 {
75         if(length!=other.length)
76                 return 0;
77
78         unsigned prefix = 0;
79         for(unsigned i=0; i<length; ++i)
80         {
81                 prefix += 8;
82                 if(data[i]!=other.data[i])
83                 {
84                         unsigned mismatch = data[i]^other.data[i];
85                         for(; mismatch; mismatch>>=1)
86                                 --prefix;
87                         break;
88                 }
89         }
90
91         return prefix;
92 }
93
94 bool Address::masked_match(const Address &other) const
95 {
96         unsigned prefix = common_prefix_length(other);
97         unsigned mask = min(mask_bits, other.mask_bits);
98         return prefix>=mask;
99 }
100
101 void Address::to_sockaddr(sockaddr_storage &sa) const
102 {
103         if(type==ETH_P_IP)
104         {
105                 sockaddr_in &sa_in = reinterpret_cast<sockaddr_in &>(sa);
106                 sa_in.sin_family = AF_INET;
107                 sa_in.sin_port = 0;
108                 sa_in.sin_addr.s_addr = *(uint32_t *)data;
109         }
110         else if(type==ETH_P_IPV6)
111         {
112                 sockaddr_in6 &sa_in6 = reinterpret_cast<sockaddr_in6 &>(sa);
113                 sa_in6.sin6_family = AF_INET6;
114                 sa_in6.sin6_port = 0;
115                 sa_in6.sin6_flowinfo = 0;
116                 copy(data, data+16, sa_in6.sin6_addr.s6_addr);
117                 sa_in6.sin6_scope_id = 0;
118         }
119         else
120                 throw runtime_error("Unknown type");
121 }
122
123 bool Address::operator<(const Address &other) const
124 {
125         if(length!=other.length)
126                 return length<other.length;
127         for(unsigned i=0; i<length; ++i)
128                 if(data[i]!=other.data[i])
129                         return data[i]<other.data[i];
130         return false;
131 }