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