1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
38 #include <anna/diameter/codec/basetypes/Address.hpp>
41 #include <arpa/inet.h>
43 #include <anna/core/functions.hpp>
46 //------------------------------------------------------------------------------
47 //------------------------------------------------------- Address::updateBasic()
48 //------------------------------------------------------------------------------
49 void anna::diameter::codec::basetypes::Address::updateBasic() throw(anna::RuntimeException) {
52 result.push_back((S8)(a_address.Version >> 8));
53 result.push_back((S8)a_address.Version);
56 if(a_address.isIPv4()) {
57 if(a_abbreviatePresentation) {
58 unsigned char buf[sizeof(struct in6_addr)];
59 int s = inet_pton(AF_INET, a_address.Value.c_str(), buf);
62 result.push_back((S8) buf[0]);
63 result.push_back((S8) buf[1]);
64 result.push_back((S8) buf[2]);
65 result.push_back((S8) buf[3]);
67 if(s < 0) perror("inet_pton");
69 throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION);
72 if(!anna::functions::isIPv4(a_address.Value))
73 throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION);
75 int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
76 sscanf(a_address.Value.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
77 result.push_back((S8) dec1);
78 result.push_back((S8) dec2);
79 result.push_back((S8) dec3);
80 result.push_back((S8) dec4);
82 } else if(a_address.isIPv6()) {
83 if(a_abbreviatePresentation) {
84 unsigned char buf[sizeof(struct in6_addr)];
85 int s = inet_pton(AF_INET6, a_address.Value.c_str(), buf);
88 result.push_back((S8) buf[0]);
89 result.push_back((S8) buf[1]);
90 result.push_back((S8) buf[2]);
91 result.push_back((S8) buf[3]);
92 result.push_back((S8) buf[4]);
93 result.push_back((S8) buf[5]);
94 result.push_back((S8) buf[6]);
95 result.push_back((S8) buf[7]);
96 result.push_back((S8) buf[8]);
97 result.push_back((S8) buf[9]);
98 result.push_back((S8) buf[10]);
99 result.push_back((S8) buf[11]);
100 result.push_back((S8) buf[12]);
101 result.push_back((S8) buf[13]);
102 result.push_back((S8) buf[14]);
103 result.push_back((S8) buf[15]);
105 if(s < 0) perror("inet_pton");
107 throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION);
110 if(!anna::functions::isIPv6(a_address.Value))
111 throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION);
113 int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
114 sscanf(a_address.Value.c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
115 result.push_back((S8)(hex1 >> 8));
116 result.push_back((S8)(hex1 & 0x00FF));
117 result.push_back((S8)(hex2 >> 8));
118 result.push_back((S8)(hex2 & 0x00FF));
119 result.push_back((S8)(hex3 >> 8));
120 result.push_back((S8)(hex3 & 0x00FF));
121 result.push_back((S8)(hex4 >> 8));
122 result.push_back((S8)(hex4 & 0x00FF));
123 result.push_back((S8)(hex5 >> 8));
124 result.push_back((S8)(hex5 & 0x00FF));
125 result.push_back((S8)(hex6 >> 8));
126 result.push_back((S8)(hex6 & 0x00FF));
127 result.push_back((S8)(hex7 >> 8));
128 result.push_back((S8)(hex7 & 0x00FF));
129 result.push_back((S8)(hex8 >> 8));
130 result.push_back((S8)(hex8 & 0x00FF));
132 } else if(a_address.isE164()) {
133 result += a_address.Value; // direct assignment
135 result += a_address.Value; // direct assignment
138 OctetString::setValue(result);
142 //------------------------------------------------------------------------------
143 //------------------------------------------------ Address::setPrintableString()
144 //------------------------------------------------------------------------------
145 void anna::diameter::codec::basetypes::Address::setPrintableString(const char * printableString) throw(anna::RuntimeException) {
146 // First: User will update child class members
148 iana_address_t address;
152 // [ Address ] ('<type (IANA Address Family Number)>|<value>' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc.
153 // Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for
154 // IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs.
155 // Currently, only IPv4, IPv6 and E164 address types have a known printable presentation)
156 std::string source = printableString;
157 size_t pipePos = source.find("|");
159 if(pipePos != std::string::npos) {
161 throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source: missing type before pipe (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
163 std::string beforePipe(printableString, pipePos);
164 address.Version = atoi(beforePipe.c_str());
165 address.Value.assign(printableString, pipePos + 1, source.size() - pipePos - 1);
167 // For backward compatibility (configurations, tests cases, etc.)
168 else { // only IPv4/v6 addresses are supported with a light checking (version pre-assumption): dot for IPv4, colon for IPv6. Anyway, updateBasic() will do regexp for supposed version
169 if(strstr(printableString, ":"))
170 address.setIPv6(printableString);
171 else if(strstr(printableString, "."))
172 address.setIPv4(printableString);
174 throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
178 setIANAAddress(address);
182 //------------------------------------------------------------------------------
183 //------------------------------------------------ Address::setPrintableString()
184 //------------------------------------------------------------------------------
185 std::string anna::diameter::codec::basetypes::Address::asPrintableString() throw(anna::RuntimeException) {
186 bool knownPrintablePresentation = (a_address.isIPv4() || a_address.isIPv6() || a_address.isE164());
188 if(!knownPrintablePresentation)
189 throw anna::RuntimeException("Address::asPrintableString | Only IPv4, IPv6 and E164 have a known printable presentation", ANNA_FILE_LOCATION);
191 return anna::functions::asString("%d|%s", a_address.getVersion(), a_address.getValue());
195 //------------------------------------------------------------------------------
196 //------------------------------------------------------------ Address::decode()
197 //------------------------------------------------------------------------------
198 void anna::diameter::codec::basetypes::Address::decode(const char* buffer, const int size) throw(anna::RuntimeException) {
200 throw anna::RuntimeException("Address::decode | Null Buffer provided", ANNA_FILE_LOCATION);
202 char str[INET6_ADDRSTRLEN];
206 throw anna::RuntimeException("Address::decode | At least 2 bytes needed to decode address version", ANNA_FILE_LOCATION);
208 a_address.Version = (((U16)buffer[0] << 8) & 0xFF00) +
209 ((U16)buffer[1] & 0x00FF); // two first octets
212 if(a_address.isIPv4()) { // 6 bytes
214 throw anna::RuntimeException("Address::decode | 2+4(=6) bytes needed to decode IPv4 address", ANNA_FILE_LOCATION);
216 if(a_abbreviatePresentation) {
217 if(inet_ntop(AF_INET, buffer + 2, str, INET_ADDRSTRLEN) != NULL) {
218 a_address.Value = str;
220 throw anna::RuntimeException("Address::decode | Error decoding IPv4 address", ANNA_FILE_LOCATION);
223 a_address.Value = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[2], (U8)buffer[3], (U8)buffer[4], (U8)buffer[5]);
225 } else if(a_address.isIPv6()) { // 18 bytes
227 throw anna::RuntimeException("Address::decode | 2+16(=18) bytes needed to decode IPv6 address", ANNA_FILE_LOCATION);
229 if(a_abbreviatePresentation) {
230 if(inet_ntop(AF_INET6, buffer + 2, str, INET6_ADDRSTRLEN) != NULL) {
231 a_address.Value = str;
233 throw anna::RuntimeException("Address::decode | Error decoding IPv6 address", ANNA_FILE_LOCATION);
236 a_address.Value = anna::functions::asString("%X:%X:%X:%X:%X:%X:%X:%X",
237 ((((U8)buffer[2]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
238 (((U8)buffer[3]) & 0x00FF),
239 ((((U8)buffer[4]) << 8) & 0xFF00) +
240 (((U8)buffer[5]) & 0x00FF),
241 ((((U8)buffer[6]) << 8) & 0xFF00) +
242 (((U8)buffer[7]) & 0x00FF),
243 ((((U8)buffer[8]) << 8) & 0xFF00) +
244 (((U8)buffer[9]) & 0x00FF),
245 ((((U8)buffer[10]) << 8) & 0xFF00) +
246 (((U8)buffer[11]) & 0x00FF),
247 ((((U8)buffer[12]) << 8) & 0xFF00) +
248 (((U8)buffer[13]) & 0x00FF),
249 ((((U8)buffer[14]) << 8) & 0xFF00) +
250 (((U8)buffer[15]) & 0x00FF),
251 ((((U8)buffer[16]) << 8) & 0xFF00) +
252 (((U8)buffer[17]) & 0x00FF));
254 } else if(a_address.isE164()) { // n bytes = 2 + address length
255 a_address.Value.assign(buffer + 2, size - 2); // Direct assignment
256 } else { // Generic decoding (could support non printable addresses but they must be...)
257 a_address.Value.assign(buffer + 2, size - 2);
260 // Base class decode()
261 OctetString::decode(buffer, size);