-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathipv6-range.c
127 lines (109 loc) · 3.22 KB
/
ipv6-range.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* ipv6-range.c - Given an IPv6 network address with prefix, calculate the
* range of IPs available.
*
* Copyright (C) 2015 - 2017, 2020 - 2021 Andrew Clayton
*
* Licensed under the GNU General Public License Version 2 or
* the GNU Lesser General Public License Version 2.1
*
* See GPLv2 & LGPLv2.1 in the source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /* UINT64_MAX */
#include <string.h>
#include <arpa/inet.h>
#include "short_types.h"
#define TXT_FMT_BOLD "\033[1m"
#define TXT_FMT_END "\033[0m"
#define HIGH_NIBBLE(byte) (((byte) >> 4) & 0x0f)
#define LOW_NIBBLE(byte) ((byte) & 0x0f)
static void pretty_print_address(const struct in6_addr *in6, u8 prefixlen)
{
const char *txtfmt = "";
for (int i = 0; i < 15; i += 2) {
if ((i*8) + 4 > prefixlen)
txtfmt = TXT_FMT_BOLD;
printf("%s%x", txtfmt, HIGH_NIBBLE(in6->s6_addr[i]));
if ((i*8) + 8 > prefixlen)
txtfmt = TXT_FMT_BOLD;
printf("%s%x", txtfmt, LOW_NIBBLE(in6->s6_addr[i]));
if (((i+1) * 8) + 4 > prefixlen)
txtfmt = TXT_FMT_BOLD;
printf("%s%x", txtfmt, HIGH_NIBBLE(in6->s6_addr[i + 1]));
if (((i+1) * 8) + 8 > prefixlen)
txtfmt = TXT_FMT_BOLD;
printf("%s%x", txtfmt, LOW_NIBBLE(in6->s6_addr[i + 1]));
if (i < 14)
printf(":");
}
printf(TXT_FMT_END"\n");
}
/*
* Based on code from https://github.com/peczenyj/IPv6SubnetCalc/
*/
static void ipv6_range(const char *network, u8 prefixlen)
{
struct in6_addr ip6b;
struct in6_addr ip6eb;
struct in6_addr ip6sb;
int i;
int len = 0;
int imask = 128 - prefixlen;
char net_s[128] = "\0";
inet_pton(AF_INET6, network, &ip6b);
for (i = 15; i >= 0; i--) {
int j = (imask > 8) ? 8 : imask;
unsigned char x = (1 << j) - 1;
ip6sb.s6_addr[i] = ip6b.s6_addr[i] & ~x;
ip6eb.s6_addr[i] = ip6b.s6_addr[i] | x;
imask -= j;
}
/*
* For a prefix length of < 64, calculate where appropriate the
* number of /48, /56, /60 and /64 networks the given network
* provides. E.g a /48 provides
*
* 256 /56s, 4096 /60s and 65536 /64s
*/
if (prefixlen < 48)
len += snprintf(net_s, sizeof(net_s), "%llu /48s, ",
1LLU << (48 - prefixlen));
if (prefixlen < 56)
len += snprintf(net_s + len, sizeof(net_s) - len,
"%llu /56s, ",
1LLU << (56 - prefixlen));
if (prefixlen < 60)
len += snprintf(net_s + len, sizeof(net_s) - len,
"%llu /60s, ",
1LLU << (60 - prefixlen));
if (prefixlen == 0)
len += snprintf(net_s + len, sizeof(net_s) - len,
"18446744073709551616 /64s");
else if (prefixlen < 64)
len += snprintf(net_s + len, sizeof(net_s) - len, "%zu /64s, ",
((u64)UINT64_MAX >> prefixlen) + 1);
net_s[len - 2] = '\0';
printf("Network : %s/%u\n\t (%s)\n", network, prefixlen, net_s);
printf("Start : ");
pretty_print_address(&ip6sb, prefixlen);
printf("End : ");
pretty_print_address(&ip6eb, prefixlen);
}
int main(int argc, char *argv[])
{
u8 prefixlen;
char *ptr;
if (argc < 2 || !strstr(argv[1], "::/")) {
printf("Usage: ipv6-range network/prefix\n");
exit(EXIT_FAILURE);
}
prefixlen = atoi(strchr(argv[1], '/') + 1);
ptr = strchr(argv[1], '/');
*ptr = '\0';
ipv6_range(argv[1], prefixlen);
printf("\nA /64 provides 18,446,744,073,709,551,616 addresses\n");
exit(EXIT_SUCCESS);
}