-subnet_t *str2net(char *subnetstr)
-{
- int i, l;
- subnet_t *subnet;
- unsigned short int x[6];
-cp
- subnet = new_subnet();
-cp
- if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
- &x[0],
- &x[1],
- &x[2],
- &x[3],
- &subnet->net.ipv4.masklength) == 5)
- {
- subnet->type = SUBNET_IPV4;
- subnet->net.ipv4.address = (((((x[0] << 8) + x[1]) << 8) + x[2]) << 8) + x[3];
- subnet->net.ipv4.mask = ~((1 << (32 - subnet->net.ipv4.masklength)) - 1);
- return subnet;
- }
-
- if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
- &subnet->net.ipv6.address.x[0],
- &subnet->net.ipv6.address.x[1],
- &subnet->net.ipv6.address.x[2],
- &subnet->net.ipv6.address.x[3],
- &subnet->net.ipv6.address.x[4],
- &subnet->net.ipv6.address.x[5],
- &subnet->net.ipv6.address.x[6],
- &subnet->net.ipv6.address.x[7],
- &subnet->net.ipv6.masklength) == 9)
- {
- subnet->type = SUBNET_IPV6;
- for(l = subnet->net.ipv6.masklength, i = 0; i < 8; l -= 16, i++)
- {
- subnet->net.ipv6.address.x[i] = htons(subnet->net.ipv6.address.x[i]);
- if(l >= 16)
- subnet->net.ipv6.mask.x[i] = 65535;
- else if (l > 0)
- subnet->net.ipv6.mask.x[i] = htons(65536 - (1 << l));
- else
- subnet->net.ipv6.mask.x[i] = 0;
- }
- return subnet;
- }
-
- if(sscanf(subnetstr, "%hu.%hu.%hu.%hu",
- &x[0],
- &x[1],
- &x[2],
- &x[3]) == 4)
- {
- subnet->type = SUBNET_IPV4;
- subnet->net.ipv4.address = (((((x[0] << 8) + x[1]) << 8) + x[2]) << 8) + x[3];
- subnet->net.ipv4.mask = ~0;
- subnet->net.ipv4.masklength = 32;
- return subnet;
- }
-
- if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
- &subnet->net.ipv6.address.x[0],
- &subnet->net.ipv6.address.x[1],
- &subnet->net.ipv6.address.x[2],
- &subnet->net.ipv6.address.x[3],
- &subnet->net.ipv6.address.x[4],
- &subnet->net.ipv6.address.x[5],
- &subnet->net.ipv6.address.x[6],
- &subnet->net.ipv6.address.x[7]) == 8)
- {
- subnet->type = SUBNET_IPV6;
- subnet->net.ipv6.masklength = 128;
- for(l = subnet->net.ipv6.masklength, i = 0; i < 8; l -= 16, i++)
- {
- subnet->net.ipv6.address.x[i] = htons(subnet->net.ipv6.address.x[i]);
- if(l >= 16)
- subnet->net.ipv6.mask.x[i] = 65535;
- else if (l > 0)
- subnet->net.ipv6.mask.x[i] = htons(65536 - (1 << l));
- else
- subnet->net.ipv6.mask.x[i] = 0;
- }
- return subnet;
- }
-
- if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
- &x[0],
- &x[1],
- &x[2],
- &x[3],
- &x[4],
- &x[5]) == 6)
- {
- subnet->type = SUBNET_MAC;
- subnet->net.mac.address.x[0] = x[0];
- subnet->net.mac.address.x[1] = x[1];
- subnet->net.mac.address.x[2] = x[2];
- subnet->net.mac.address.x[3] = x[3];
- subnet->net.mac.address.x[4] = x[4];
- subnet->net.mac.address.x[5] = x[5];
- return subnet;
- }
-
- free(subnet);
- return NULL;
+bool str2net(subnet_t *subnet, const char *subnetstr) {
+ char str[64];
+ strncpy(str, subnetstr, sizeof(str));
+ str[sizeof(str) - 1] = 0;
+ int consumed;
+
+ int weight = 10;
+ char *weight_separator = strchr(str, '#');
+
+ if(weight_separator) {
+ char *weight_str = weight_separator + 1;
+
+ if(sscanf(weight_str, "%d%n", &weight, &consumed) < 1) {
+ return false;
+ }
+
+ if(weight_str[consumed]) {
+ return false;
+ }
+
+ *weight_separator = 0;
+ }
+
+ int prefixlength = -1;
+ char *prefixlength_separator = strchr(str, '/');
+
+ if(prefixlength_separator) {
+ char *prefixlength_str = prefixlength_separator + 1;
+
+ if(sscanf(prefixlength_str, "%d%n", &prefixlength, &consumed) < 1) {
+ return false;
+ }
+
+ if(prefixlength_str[consumed]) {
+ return false;
+ }
+
+ *prefixlength_separator = 0;
+
+ if(prefixlength < 0) {
+ return false;
+ }
+ }
+
+ uint16_t x[8];
+
+ if(sscanf(str, "%hx:%hx:%hx:%hx:%hx:%hx%n", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &consumed) >= 6 && !str[consumed]) {
+ /*
+ Normally we should check that each part has two digits to prevent ambiguities.
+ However, in old tinc versions net2str() will aggressively return MAC addresses with one-digit parts,
+ so we have to accept them otherwise we would be unable to parse ADD_SUBNET messages.
+ */
+ if(prefixlength >= 0) {
+ return false;
+ }
+
+ subnet->type = SUBNET_MAC;
+ subnet->weight = weight;
+
+ for(int i = 0; i < 6; i++) {
+ subnet->net.mac.address.x[i] = x[i];
+ }
+
+ return true;
+ }
+
+ if(inet_pton(AF_INET, str, &subnet->net.ipv4.address)) {
+ if(prefixlength == -1) {
+ prefixlength = 32;
+ }
+
+ if(prefixlength > 32) {
+ return false;
+ }
+
+ subnet->type = SUBNET_IPV4;
+ subnet->net.ipv4.prefixlength = prefixlength;
+ subnet->weight = weight;
+
+ return true;
+ }
+
+ if(inet_pton(AF_INET6, str, &subnet->net.ipv6.address)) {
+ if(prefixlength == -1) {
+ prefixlength = 128;
+ }
+
+ if(prefixlength > 128) {
+ return false;
+ }
+
+ subnet->type = SUBNET_IPV6;
+ subnet->net.ipv6.prefixlength = prefixlength;
+ subnet->weight = weight;
+
+ return true;
+ }
+
+ return false;