summaryrefslogtreecommitdiff
path: root/calc.c
blob: ddcfe957135b81457675f3495c806a157049dc86 (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
#include "calc.h"
#include "itoa_lut.h"
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.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 = {.bits = itoa_lut[(ip >> 24) & 0xff]};
    WRITE_STR(ptr, e.fields.chars, e.fields.len)
    ptr[0] = '.';
    ptr += 1;
    e.bits = itoa_lut[(ip >> 16) & 0xff];
    WRITE_STR(ptr, e.fields.chars, e.fields.len)
    ptr[0] = '.';
    ptr += 1;
    e.bits = itoa_lut[(ip >> 8) & 0xff];
    WRITE_STR(ptr, e.fields.chars, e.fields.len)
    ptr[0] = '.';
    ptr += 1;
    e.bits = itoa_lut[ip & 0xff];
    WRITE_STR(ptr, e.fields.chars, e.fields.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 = {.bits = itoa_lut[ips_per_subnet - 2]};
        WRITE_STR(chunk_ptr, e.fields.chars, e.fields.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);
    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;
}