Canonicalize CIDR: Difference between revisions
Content added Content deleted
(Added C solution) |
|||
Line 4: | Line 4: | ||
Example: given 87.70.141.1/22, your code should output 87.70.140.0/22. |
Example: given 87.70.141.1/22, your code should output 87.70.140.0/22. |
||
=={{header|C}}== |
|||
This solution uses only the standard library. On POSIX platforms one can use the functions |
|||
inet_pton/inet_ntop to parse/format IPv4 addresses. |
|||
<lang c>#include <stdbool.h> |
|||
#include <stdio.h> |
|||
#include <stdint.h> |
|||
typedef struct cidr_tag { |
|||
uint32_t address; |
|||
uint32_t mask; |
|||
} cidr_t; |
|||
// Convert a string in CIDR format to an IPv4 address and netmask, |
|||
// if possible. Also performs CIDR canonicalization. |
|||
bool cidr_parse(const char* str, cidr_t* cidr) { |
|||
int a, b, c, d, m; |
|||
if (sscanf(str, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &m) != 5) |
|||
return false; |
|||
if (m < 1 || m > 32) |
|||
return false; |
|||
if (a < 0 || a > UINT8_MAX) |
|||
return false; |
|||
if (b < 0 || b > UINT8_MAX) |
|||
return false; |
|||
if (c < 0 || c > UINT8_MAX) |
|||
return false; |
|||
if (d < 0 || d > UINT8_MAX) |
|||
return false; |
|||
uint32_t mask = ~((1 << (32 - m)) - 1); |
|||
uint32_t address = (a << 24) + (b << 16) + (c << 8) + d; |
|||
address &= mask; |
|||
cidr->address = address; |
|||
cidr->mask = mask; |
|||
return true; |
|||
} |
|||
uint8_t mask_length(uint32_t mask) { |
|||
uint8_t length = 32; |
|||
for (; (mask & 1) == 0 && length > 0; mask >>= 1, --length) {} |
|||
return length; |
|||
} |
|||
// Write a string in CIDR notation into the supplied buffer. |
|||
void cidr_format(const cidr_t* cidr, char* str, size_t size) { |
|||
uint8_t m = mask_length(cidr->mask); |
|||
uint32_t address = cidr->address; |
|||
uint8_t d = address & UINT8_MAX; |
|||
address >>= 8; |
|||
uint8_t c = address & UINT8_MAX; |
|||
address >>= 8; |
|||
uint8_t b = address & UINT8_MAX; |
|||
address >>= 8; |
|||
uint8_t a = address & UINT8_MAX; |
|||
snprintf(str, size, "%hhu.%hhu.%hhu.%hhu/%hhu", a, b, c, d, m); |
|||
} |
|||
int main(int argc, char** argv) { |
|||
for (int i = 1; i < argc; ++i) { |
|||
cidr_t cidr; |
|||
if (cidr_parse(argv[i], &cidr)) { |
|||
char out[32]; |
|||
cidr_format(&cidr, out, sizeof(out)); |
|||
puts(out); |
|||
} else { |
|||
fprintf(stderr, "%s: invalid CIDR\n", argv[i]); |
|||
} |
|||
} |
|||
return 0; |
|||
}</lang> |
|||
{{out}} |
|||
<pre> |
|||
$ ./canonicalize_cidr 87.70.141.1/22 |
|||
87.70.140.0/22 |
|||
</pre> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |