1 #include "massip.h"
2 #include "massip-parse.h"
3 #include "massip-rangesv4.h"
4 #include "massip-rangesv6.h"
5 #include <string.h>
6 #include <ctype.h>
7 
massip_apply_excludes(struct MassIP * targets,struct MassIP * exclude)8 void massip_apply_excludes(struct MassIP *targets, struct MassIP *exclude)
9 {
10     rangelist_exclude(&targets->ipv4, &exclude->ipv4);
11     range6list_exclude(&targets->ipv6, &exclude->ipv6);
12     rangelist_exclude(&targets->ports, &exclude->ports);
13 }
14 
massip_optimize(struct MassIP * targets)15 void massip_optimize(struct MassIP *targets)
16 {
17     rangelist_optimize(&targets->ipv4);
18     range6list_optimize(&targets->ipv6);
19     rangelist_optimize(&targets->ports);
20 
21     targets->count_ports = rangelist_count(&targets->ports);
22     targets->count_ipv4s = rangelist_count(&targets->ipv4);
23     targets->count_ipv6s = range6list_count(&targets->ipv6).lo;
24     targets->ipv4_index_threshold = targets->count_ipv4s * rangelist_count(&targets->ports);
25 }
26 
massip_pick(const struct MassIP * massip,uint64_t index,ipaddress * addr,unsigned * port)27 int massip_pick(const struct MassIP *massip, uint64_t index, ipaddress *addr, unsigned *port)
28 {
29     /*
30      * We can return either IPv4 or IPv6 addresses
31      */
32     if (index < massip->ipv4_index_threshold) {
33         addr->version = 4;
34         addr->ipv4 = rangelist_pick(&massip->ipv4, index % massip->count_ipv4s);
35         *port = rangelist_pick(&massip->ports, index / massip->count_ipv4s);
36     } else {
37         addr->version = 6;
38         index -= massip->ipv4_index_threshold;
39         addr->ipv6 = range6list_pick(&massip->ipv6, index % massip->count_ipv6s);
40         *port = rangelist_pick(&massip->ports, index / massip->count_ipv6s);
41     }
42     return 0;
43 }
44 
massip_has_ip(const struct MassIP * massip,ipaddress ip)45 int massip_has_ip(const struct MassIP *massip, ipaddress ip)
46 {
47     if (ip.version == 6)
48         return range6list_is_contains(&massip->ipv6, ip.ipv6);
49     else
50         return rangelist_is_contains(&massip->ipv4, ip.ipv4);
51 }
52 
massip_has_port(const struct MassIP * massip,unsigned port)53 int massip_has_port(const struct MassIP *massip, unsigned port)
54 {
55     return rangelist_is_contains(&massip->ports, port);
56 }
57 
massip_has_ipv4_targets(const struct MassIP * massip)58 int massip_has_ipv4_targets(const struct MassIP *massip)
59 {
60     return massip->ipv4.count != 0;
61 }
massip_has_target_ports(const struct MassIP * massip)62 int massip_has_target_ports(const struct MassIP *massip)
63 {
64     return massip->ports.count != 0;
65 }
massip_has_ipv6_targets(const struct MassIP * massip)66 int massip_has_ipv6_targets(const struct MassIP *massip)
67 {
68     return massip->ipv6.count != 0;
69 }
70 
71 
massip_add_target_string(struct MassIP * massip,const char * string)72 int massip_add_target_string(struct MassIP *massip, const char *string)
73 {
74     const char *ranges = string;
75     size_t offset = 0;
76     size_t max_offset = strlen(ranges);
77 
78     while (offset < max_offset) {
79         struct Range range;
80         struct Range6 range6;
81         int err;
82 
83         /* Grab the next IPv4 or IPv6 range */
84         err = massip_parse_range(ranges, &offset, max_offset, &range, &range6);
85         switch (err) {
86         case Ipv4_Address:
87             rangelist_add_range(&massip->ipv4, range.begin, range.end);
88             break;
89         case Ipv6_Address:
90             range6list_add_range(&massip->ipv6, range6.begin, range6.end);
91             break;
92         default:
93             offset = max_offset; /* An error means skipping the rest of the string */
94             return 1;
95         }
96         while (offset < max_offset && (isspace(ranges[offset]&0xFF) || ranges[offset] == ','))
97             offset++;
98     }
99     return 0;
100 }
101 
massip_add_port_string(struct MassIP * targets,const char * string,unsigned defaultrange)102 int massip_add_port_string(struct MassIP *targets, const char *string, unsigned defaultrange)
103 {
104     unsigned is_error = 0;
105     rangelist_parse_ports(&targets->ports, string, &is_error, defaultrange);
106     if (is_error)
107         return 1;
108     else
109         return 0;
110 }
111 
massip_selftest(void)112 int massip_selftest(void)
113 {
114     struct MassIP targets;
115     struct MassIP excludes;
116     int err;
117     int line;
118     massint128_t count;
119 
120     memset(&targets, 0, sizeof(targets));
121     memset(&excludes, 0, sizeof(targets));
122 
123     rangelist_parse_ports(&targets.ports, "80", 0, 0);
124 
125     /* First, create a list of targets */
126     line = __LINE__;
127     err = massip_add_target_string(&targets, "2607:f8b0:4002:801::2004/124,1111::1");
128     if (err)
129         goto fail;
130 
131     /* Second, create an exclude list */
132     line = __LINE__;
133     err = massip_add_target_string(&excludes, "2607:f8b0:4002:801::2004/126,1111::/16");
134     if (err)
135         goto fail;
136 
137     /* Third, apply the excludes, causing ranges to be removed
138      * from the target list */
139     massip_apply_excludes(&targets, &excludes);
140 
141     /* Now make sure the count equals the expected count */
142     line = __LINE__;
143     count = massip_range(&targets);
144     if (count.hi != 0 || count.lo != 12)
145         goto fail;
146 
147     return 0;
148 fail:
149     fprintf(stderr, "[-] massip: test fail, line=%d\n", line);
150     return 1;
151 }
152 
153