summaryrefslogtreecommitdiff
path: root/calc.c
blob: fb0a5a47b8fa09f9a916ed5dfb1cc40efdf59491 (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "calc.h"
#include "itoa_lut.h"
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>

int print_usage() {
    printf("Invalid arguments:\n\tcalc <network/cidr> <ips per subnet>\n");

    return 1;
}

uint32_t calc_netmask(unsigned int cidr) {
    return UINT32_MAX << (32 - cidr);
}

uint32_t segments_to_ip(unsigned int segments[4]) {
    return (segments[0] << 3*8) | (segments[1] << 2*8) | (segments[2] << 1*8) | (segments[3]);
}

uint32_t subnetmask_for_netspace(unsigned int desired_netspace) {
    uint32_t start = UINT32_MAX;
    // +1 because 2s complement
    while (~start +1 < desired_netspace + 2) {
        start = start << 1;
    }
    return start;
}

void write_ip(char **chunk_ptr, uint32_t ip) {
    // local ptr so we don't have to deref every time
    char *ptr = *chunk_ptr;
    LutEntry e = itoa_lut[(ip >> 24) & 0xff];
    WRITE_STR(ptr, e.chars, e.len)
    ptr[0] = '.';
    ptr += 1;
    e = itoa_lut[(ip >> 16) & 0xff];
    WRITE_STR(ptr, e.chars, e.len)
    ptr[0] = '.';
    ptr += 1;
    e = itoa_lut[(ip >> 8) & 0xff];
    WRITE_STR(ptr, e.chars, e.len)
    ptr[0] = '.';
    ptr += 1;
    e = itoa_lut[ip & 0xff];
    WRITE_STR(ptr, e.chars, e.len)
    *chunk_ptr = ptr;
}

int main(int argc, char** argv) {
    struct timespec start;
    clock_gettime(CLOCK_MONOTONIC, &start);

    unsigned int segments[4] = {0};
    unsigned int cidr = 0;
    unsigned int min_ips_per_subnet = 0;
    // parse args
    if (argc < 3) {
        return print_usage();
    }
    if (sscanf(argv[1], "%u.%u.%u.%u/%u", &segments[0], &segments[1], &segments[2], &segments[3], &cidr) != 5) return print_usage();
    if (sscanf(argv[2], "%u", &min_ips_per_subnet) != 1) return print_usage();

    CalcRequest req = {
        .network = segments_to_ip(segments), // fixed later
        .netmask = calc_netmask(cidr),
        .subnet_mask = subnetmask_for_netspace(min_ips_per_subnet),
        .count = 0, // later
    };
    // User can provide any ip address, this converts it to the network address
    req.network = req.network & req.netmask;
    // +1 because 2s complement
    const unsigned int ips_per_subnet = ~req.subnet_mask + 1;
    req.count = (~req.netmask+1) / (ips_per_subnet);

    FILE *out = fopen("file.json", "w");
    if (out == NULL) {
        perror("Failed to open output file:");
        return errno;
    }


    fprintf(out, "[\n"); // file start
    uint32_t offset = 0;
    int i = 0;
    char chunk[1024] = {0}; 
    while (i<req.count) {
        const uint32_t network = req.network + offset;
        const uint32_t first = network + 1;
        const uint32_t broadcast = first + ips_per_subnet - 2;
        const uint32_t last = broadcast - 1;
        offset += ips_per_subnet;
        char* chunk_ptr = chunk;
        WRITE_STR(chunk_ptr,  "\t{\n\t\t\"Reseau\": \"", 16)
        write_ip(&chunk_ptr, network);
        WRITE_STR(chunk_ptr,  "\",\n", 3)
        WRITE_STR(chunk_ptr,  "\t\t\"Premiere\": \"", 15)
        write_ip(&chunk_ptr, first);
        WRITE_STR(chunk_ptr,  "\",\n", 3)
        WRITE_STR(chunk_ptr,  "\t\t\"Derniere\": \"", 15)
        write_ip(&chunk_ptr, last);
        WRITE_STR(chunk_ptr,  "\",\n", 3)
        WRITE_STR(chunk_ptr,  "\t\t\"Broadcast\": \"", 16)
        write_ip(&chunk_ptr, broadcast);
        WRITE_STR(chunk_ptr,  "\",\n", 3)
        WRITE_STR(chunk_ptr,  "\t\t\"Nbr\": \"", 10)
        LutEntry e = itoa_lut[ips_per_subnet - 2];
        WRITE_STR(chunk_ptr, e.chars, e.len);
        if (i+1 == req.count) {
            WRITE_STR(chunk_ptr,  "\"\n\t}\n", 5)
        }else {
            WRITE_STR(chunk_ptr,  "\"\n\t},\n", 6)
        }

        fwrite(chunk, sizeof(char), chunk_ptr - chunk, out);
        i++;
    }
    fprintf(out, "]"); // file end
    fflush(out);
    sync();
    fclose(out);

    struct timespec end;
    clock_gettime(CLOCK_MONOTONIC, &end);

    printf("Time elapsed: %llu ms\n", (unsigned long long)((end.tv_sec - start.tv_sec) * 1e3 + (end.tv_nsec - start.tv_nsec) / 1e6));

    return 0;
}