diff options
Diffstat (limited to 'src/sg.c')
-rw-r--r-- | src/sg.c | 129 |
1 files changed, 121 insertions, 8 deletions
@@ -15,6 +15,8 @@ along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ #include "eclat.h" +#include <arpa/inet.h> +#include <netdb.h> #define GROUP_ID 0 #define GROUP_NAME 1 @@ -48,6 +50,113 @@ static char *from_port, *to_port; static char *bufptr = NULL; static size_t bufsize = 0; +static int +add_source_cidr(char *str, int i) +{ + char *p; + struct in_addr addr; + unsigned long n; + char masklen[3]; + char cidrbuf[19]; + struct addrinfo hints, *res, *ap; + struct protoent *pe; + + p = strchr(str, '/'); + if (p) { + char *q; + + *p++ = 0; + n = strtoul(p, &q, 10); + if (*q == 0) { + if (n <= 0 || n > 32) { + p[-1] = '/'; + die(EX_USAGE, "invalid network mask in %s", + str); + } + strcpy(masklen, p); + } else { + int j; + + if (inet_aton(p, &addr) == 0) { + p[-1] = '/'; + die(EX_USAGE, "invalid network mask in %s", + str); + } + n = addr.s_addr; + for (j = 0; j < 32 && (n & 1); j++, n >>= 1) + ; + if (n) { + p[-1] = '/'; + die(EX_USAGE, "invalid network mask in %s", + str); + } + masklen[0] = j/10 + '0'; + masklen[1] = j%10 + '0'; + masklen[2] = 0; + } + } else + strcpy(masklen, "32"); + + memset(&hints, 0, sizeof(hints)); + pe = getprotobyname(proto); + if (pe) + hints.ai_protocol = pe->p_proto; + else { + errno = 0; + n = strtoul(proto, &p, 0); + if (errno || *p) + die(EX_USAGE, "%s: unrecognized protocol"); + hints.ai_protocol = n; + } + hints.ai_family = AF_INET; + + if (getaddrinfo(str, NULL, &hints, &res)) { + p[-1] = '/'; + die(EX_USAGE, "invalid network address in %s", str); + } + + for (ap = res; ap; ap = ap->ai_next) { + struct sockaddr_in *sp = (struct sockaddr_in *) ap->ai_addr; + char *s = inet_ntoa(sp->sin_addr); + if (s) { + snprintf(cidrbuf, sizeof cidrbuf, + "%s/%s", s, masklen); + grecs_asprintf(&bufptr, &bufsize, + "IpPermissions.%d.IpRanges.%d.CidrIp", + rule_n, i); + eclat_query_add_param(query, bufptr, cidrbuf); + i++; + } + } + freeaddrinfo(res); + + return i; +} + +static char * +str2port(const char *str, char **pbuf, size_t *psize) +{ + unsigned long n; + struct servent *p; + char *end; + + p = getservbyname(str, proto); + if (p) { + grecs_asprintf(pbuf, psize, "%d", (int) ntohs(p->s_port)); + return *pbuf; + } + + errno = 0; + n = strtoul(str, &end, 10); + if (errno) + die(EX_USAGE, "%s: invalid port: %s", str, strerror(errno)); + if (*end) + die(EX_USAGE, "%s: invalid port", str); + if (n == 0 || n > USHRT_MAX) + die(EX_USAGE, "%s: port number out of range", str); + return (char *) str; +} + static void flush_rule() { @@ -77,12 +186,10 @@ flush_rule() grecs_list_clear(group_list); } if (source_list) { - for (i = 1, ep = source_list->head; ep; ep = ep->next, i++) { - grecs_asprintf(&bufptr, &bufsize, - "IpPermissions.%d.IpRanges.%d.CidrIp", - rule_n, i); - eclat_query_add_param(query, bufptr, (char*) ep->data); - } + int j = 1; + + for (i = 1, ep = source_list->head; ep; ep = ep->next, i++) + j = add_source_cidr((char*) ep->data, j); grecs_list_clear(source_list); } else if (!group_list) { grecs_asprintf(&bufptr, &bufsize, @@ -92,12 +199,18 @@ flush_rule() } if (from_port) { + char *pbuf = NULL; + size_t psize = 0; + grecs_asprintf(&bufptr, &bufsize, "IpPermissions.%d.FromPort", rule_n); - eclat_query_add_param(query, bufptr, from_port); + eclat_query_add_param(query, bufptr, + str2port(from_port, &pbuf, &psize)); grecs_asprintf(&bufptr, &bufsize, "IpPermissions.%d.ToPort", rule_n); - eclat_query_add_param(query, bufptr, to_port); + eclat_query_add_param(query, bufptr, + str2port(to_port, &pbuf, &psize)); + free(pbuf); } from_port = to_port = NULL; ++rule_n; |