summaryrefslogtreecommitdiff
path: root/src/check_prefix_boundary.c
blob: b432c788e41958b7897a068d111bec4adf7374ef (plain)
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
#include "check_ucast_static.h"

static void usage(void)
{
	fprintf(stderr, "Usage: check-prefix-boundary [-4|-6] address/prefix\n");
	exit(1);
}

static void get_prefix_1(inet_prefix *dst, char *arg, int family)
{
	char *slash, *endp;

	memset(dst, 0, sizeof(*dst));

	slash = strchr(arg, '/');
	if (!slash || slash[1] == '\0')
		err("Missing prefix length\n");
	*slash = 0;

	get_addr_1(dst, arg, family);

	dst->plen = strtoul(slash+1, &endp, 0);
	if (*endp != '\0')
		err("Invalid character in prefix length\n");

	if (dst->plen > 8 * dst->bytelen)
		err("Prefix length is too large\n");

	*slash = '/';
}

static void get_netmask(inet_prefix *msk, const inet_prefix *dst)
{
	int i, plen = dst->plen;

	memset(msk, 0, sizeof(*msk));
	msk->family = dst->family;
	msk->bytelen = dst->bytelen;

	for (i = 0; plen > 0 && i < dst->bytelen / sizeof(uint32_t); i++) {
		uint32_t m = (plen > 32) ? ~0 : htonl(~0 << (32 - plen));
		
		msk->data[i] = dst->data[i] & m;
		plen -= 32;
	}
}

int main(int argc, char **argv)
{
	int family = AF_UNSPEC;
    
	while (--argc) {
		char *arg = *++argv;
		inet_prefix dst, msk;

		if (arg[0] == '-') { 
			switch(arg[1]) {
			case '4':
				family = AF_INET;
				break;
			case '6':
				family = AF_INET6;
				break;
			default:
				usage();
			}
            continue;
        }

		get_prefix_1(&dst, arg, family);
		get_netmask(&msk, &dst);
		
		if (memcmp(msk.data, dst.data, dst.bytelen) != 0) {
			char buf[INET_ADDRSTRLEN];
			err("Prefix not on a natural network boundary."
			    "Did you mean %s?\n", 
			    inet_ntop(msk.family, msk.data, buf, sizeof buf));
		}

        /*
         * Macros to check for Mcast are based on:
         *
         *    Addr          dst.data
         * 224.1.2.2    ==> 0x030201e0
         * ff01:0203::  ==> 0x030201ff
         *
         */
        if (family == AF_INET) {
            if (IS_MULTICAST(dst.data[0])) {
                err("Invalid Prefix...Route cannot be Multicast\n");
            } 
            if (IS_BROADCAST(dst.data[0])) {
                err("Invalid Prefix...Route cannot be Broadcast\n");
            } 
        } else if (family == AF_INET6) {
            if (IS_IPV6_MULTICAST(dst.data[0])) {
                err("Invalid Prefix...Route cannot be IPv6 Multicast\n");
            } 
        }

	}

	return 0;
}