static bool validate_end(struct ub_ctx *dnsctx , #endif struct starter_conn *conn_st, struct starter_end *end, const char *leftright, bool resolvip UNUSED, err_t *perr) { err_t er = NULL; char *err_str = NULL; int family = conn_st->options[KBF_CONNADDRFAMILY]; bool err = FALSE; # define ERR_FOUND(...) { err |= error_append(&err_str, __VA_ARGS__); } if (!end->options_set[KNCF_IP]) conn_st->state = STATE_INCOMPLETE; end->addrtype = end->options[KNCF_IP]; end->addr_family = family; /* validate the KSCF_IP/KNCF_IP */ switch (end->addrtype) { case KH_ANY: anyaddr(family, &(end->addr)); break; case KH_IFACE: /* generally, this doesn't show up at this stage */ starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_IFACE", leftright); break; case KH_IPADDR: assert(end->strings[KSCF_IP] != NULL); if (end->strings[KSCF_IP][0] == '%') { pfree(end->iface); end->iface = clone_str(end->strings[KSCF_IP] + 1, "KH_IPADDR end->iface"); if (!starter_iface_find(end->iface, family, &end->addr, &end->nexthop)) conn_st->state = STATE_INVALID; /* not numeric, so set the type to the iface type */ end->addrtype = KH_IFACE; break; } er = ttoaddr_num(end->strings[KNCF_IP], 0, family, &(end->addr)); if (er != NULL) { /* not numeric, so set the type to the string type */ end->addrtype = KH_IPHOSTNAME; } if (end->id == NULL) { ipstr_buf b; end->id = clone_str(ipstr(&end->addr, &b), "end if"); } break; case KH_OPPO: conn_st->policy |= POLICY_OPPORTUNISTIC; break; case KH_OPPOGROUP: conn_st->policy |= POLICY_OPPORTUNISTIC | POLICY_GROUP; break; case KH_GROUP: conn_st->policy |= POLICY_GROUP; break; case KH_IPHOSTNAME: /* generally, this doesn't show up at this stage */ starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_IPHOSTNAME", leftright); break; case KH_DEFAULTROUTE: starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_DEFAULTROUTE", leftright); break; case KH_NOTSET: starter_log(LOG_LEVEL_DEBUG, "starter: %s is KH_NOTSET", leftright); break; } /* validate the KSCF_SUBNET */ if (end->strings_set[KSCF_SUBNET]) { char *value = end->strings[KSCF_SUBNET]; if (end->strings_set[KSCF_ADDRESSPOOL]) { ERR_FOUND("cannot specify both %ssubnet= and %saddresspool=", leftright, leftright); } if (startswith(value, "vhost:") || startswith(value, "vnet:")) { er = NULL; end->virt = clone_str(value, "validate_end item"); } else { end->has_client = TRUE; er = ttosubnet(value, 0, family, &(end->subnet)); } if (er != NULL) ERR_FOUND("bad subnet %ssubnet=%s [%s]", leftright, value, er); } /* set nexthop address to something consistent, by default */ anyaddr(family, &end->nexthop); anyaddr(addrtypeof(&end->addr), &end->nexthop); /* validate the KSCF_NEXTHOP */ if (end->strings_set[KSCF_NEXTHOP]) { char *value = end->strings[KSCF_NEXTHOP]; if (strcaseeq(value, "%defaultroute")) { end->nexttype = KH_DEFAULTROUTE; } else { if (tnatoaddr(value, strlen(value), AF_INET, &(end->nexthop)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->nexthop)) != NULL) { #ifdef DNSSEC starter_log(LOG_LEVEL_DEBUG, "Calling unbound_resolve() for %snexthop value", leftright); if (!unbound_resolve(dnsctx, value, strlen(value), AF_INET, &(end->nexthop)) && !unbound_resolve(dnsctx, value, strlen(value), AF_INET6, &(end->nexthop))) ERR_FOUND("bad value for %snexthop=%s\n", leftright, value); #else er = ttoaddr(value, 0, family, &(end->nexthop)); if (er != NULL) ERR_FOUND("bad value for %snexthop=%s [%s]", leftright, value, er); #endif } end->nexttype = KH_IPADDR; } } else { #if 0 if (conn_st->policy & POLICY_OPPORTUNISTIC) end->nexttype = KH_DEFAULTROUTE; #endif anyaddr(family, &end->nexthop); if (end->addrtype == KH_DEFAULTROUTE) { end->nexttype = KH_DEFAULTROUTE; } } /* validate the KSCF_ID */ if (end->strings_set[KSCF_ID]) { char *value = end->strings[KSCF_ID]; pfreeany(end->id); end->id = clone_str(value, "end->id"); } if (end->options_set[KSCF_RSAKEY1]) { end->rsakey1_type = end->options[KSCF_RSAKEY1]; end->rsakey2_type = end->options[KSCF_RSAKEY2]; switch (end->options[KSCF_RSAKEY1]) { case PUBKEY_DNS: case PUBKEY_DNSONDEMAND: end->key_from_DNS_on_demand = TRUE; break; default: end->key_from_DNS_on_demand = FALSE; /* validate the KSCF_RSAKEY1/RSAKEY2 */ if (end->strings[KSCF_RSAKEY1] != NULL) { char *value = end->strings[KSCF_RSAKEY1]; pfreeany(end->rsakey1); end->rsakey1 = (unsigned char *)clone_str(value,"end->rsakey1"); } if (end->strings[KSCF_RSAKEY2] != NULL) { char *value = end->strings[KSCF_RSAKEY2]; pfreeany(end->rsakey2); end->rsakey2 = (unsigned char *)clone_str(value,"end->rsakey2"); } } } /* validate the KSCF_SOURCEIP, if any, and if set, * set the subnet to same value, if not set. */ if (end->strings_set[KSCF_SOURCEIP]) { char *value = end->strings[KSCF_SOURCEIP]; if (tnatoaddr(value, strlen(value), AF_INET, &(end->sourceip)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->sourceip)) != NULL) { #ifdef DNSSEC starter_log(LOG_LEVEL_DEBUG, "Calling unbound_resolve() for %ssourceip value", leftright); if (!unbound_resolve(dnsctx, value, strlen(value), AF_INET, &(end->sourceip)) && !unbound_resolve(dnsctx, value, strlen(value), AF_INET6, &(end->sourceip))) ERR_FOUND("bad value for %ssourceip=%s\n", leftright, value); #else er = ttoaddr(value, 0, family, &(end->sourceip)); if (er != NULL) ERR_FOUND("bad addr %ssourceip=%s [%s]", leftright, value, er); #endif } else { er = tnatoaddr(value, 0, family, &(end->sourceip)); if (er != NULL) ERR_FOUND("bad numerical addr %ssourceip=%s [%s]", leftright, value, er); } if (!end->has_client) { starter_log(LOG_LEVEL_INFO, "%ssourceip= used but not %ssubnet= defined, defaulting %ssubnet to %s", leftright, leftright, leftright, value); er = addrtosubnet(&end->sourceip, &end->subnet); if (er != NULL) { ERR_FOUND("attempt to default %ssubnet from %s failed: %s", leftright, value, er); } end->has_client = TRUE; end->has_client_wildcard = FALSE; } } /* copy certificate path name */ if (end->strings_set[KSCF_CERT]) end->cert = clone_str(end->strings[KSCF_CERT], "KSCF_CERT"); if (end->strings_set[KSCF_CA]) end->ca = clone_str(end->strings[KSCF_CA], "KSCF_CA"); if (end->strings_set[KSCF_UPDOWN]) end->updown = clone_str(end->strings[KSCF_UPDOWN], "KSCF_UPDOWN"); if (end->strings_set[KSCF_PROTOPORT]) { err_t ugh; char *value = end->strings[KSCF_PROTOPORT]; ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &end->has_port_wildcard); if (ugh != NULL) ERR_FOUND("bad %sprotoport=%s [%s]", leftright, value, ugh); } if (end->strings_set[KSCF_ADDRESSPOOL]) { char *addresspool = end->strings[KSCF_ADDRESSPOOL]; if (end->strings_set[KSCF_SUBNET]) ERR_FOUND("cannot specify both %ssubnet= and %saddresspool=", leftright, leftright); starter_log(LOG_LEVEL_DEBUG, "connection's %saddresspool set to: %s", leftright, end->strings[KSCF_ADDRESSPOOL] ); er = ttorange(addresspool, 0, AF_INET, &end->pool_range, TRUE); if (er != NULL) ERR_FOUND("bad %saddresspool=%s [%s]", leftright, addresspool, er); } if (end->options_set[KNCF_XAUTHSERVER] || end->options_set[KNCF_XAUTHCLIENT]) conn_st->policy |= POLICY_XAUTH; /* KSCF_SUBNETWITHIN --- not sure what to do with it. KSCF_ESPENCKEY --- todo (manual keying) KSCF_ESPAUTHKEY --- todo (manual keying) KSCF_SOURCEIP = 16, KSCF_MAX = 19 */ if (err) *perr = err_str; return err; # undef ERR_FOUND }
static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token, kw_list_t *kw, char *conn_name, starter_config_t *cfg) { err_t ugh = NULL; bool assigned = FALSE; bool has_port_wildcard; /* set if port is %any */ char *name = kw->entry->name; char *value = kw->value; if (!assign_arg(token, KW_END_FIRST, kw, (char *)end, &assigned)) goto err; /* post processing of some keywords that were assigned automatically */ switch (token) { case KW_SUBNET: if ((strlen(value) >= 6 && strncmp(value,"vhost:",6) == 0) || (strlen(value) >= 5 && strncmp(value,"vnet:",5) == 0)) { /* used by pluto only */ end->has_virt = TRUE; } else { ip_subnet net; char *pos; int len = 0; end->has_client = TRUE; conn->tunnel_addr_family = ip_version(value); pos = strchr(value, ','); if (pos) { len = pos - value; } ugh = ttosubnet(value, len, ip_version(value), &net); if (ugh != NULL) { plog("# bad subnet: %s=%s [%s]", name, value, ugh); goto err; } } break; case KW_SOURCEIP: if (end->has_natip) { plog("# natip and sourceip cannot be defined at the same time"); goto err; } if (value[0] == '%') { if (streq(value, "%modeconfig") || streq(value, "%modecfg") || streq(value, "%config") || streq(value, "%cfg")) { /* request ip via config payload */ free(end->sourceip); end->sourceip = NULL; end->sourceip_mask = 1; } else { /* %poolname, strip %, serve ip requests */ free(end->sourceip); end->sourceip = clone_str(value+1); end->sourceip_mask = 0; } end->modecfg = TRUE; } else { char *pos; ip_address addr; ip_subnet net; conn->tunnel_addr_family = ip_version(value); pos = strchr(value, '/'); if (pos) { /* CIDR notation, address pool */ ugh = ttosubnet(value, 0, conn->tunnel_addr_family, &net); if (ugh != NULL) { plog("# bad subnet: %s=%s [%s]", name, value, ugh); goto err; } *pos = '\0'; free(end->sourceip); end->sourceip = clone_str(value); end->sourceip_mask = atoi(pos + 1); } else { /* fixed srcip */ ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &addr); if (ugh != NULL) { plog("# bad addr: %s=%s [%s]", name, value, ugh); goto err; } end->sourceip_mask = (conn->tunnel_addr_family == AF_INET) ? 32 : 128; } } conn->policy |= POLICY_TUNNEL; break; case KW_SENDCERT: if (end->sendcert == CERT_YES_SEND) { end->sendcert = CERT_ALWAYS_SEND; } else if (end->sendcert == CERT_NO_SEND) { end->sendcert = CERT_NEVER_SEND; } break; default: break; } if (assigned) return; /* individual processing of keywords that were not assigned automatically */ switch (token) { case KW_HOST: if (streq(value, "%defaultroute")) { if (cfg->defaultroute.defined) { end->addr = cfg->defaultroute.addr; end->nexthop = cfg->defaultroute.nexthop; } else if (!cfg->defaultroute.supported) { plog("%%defaultroute not supported, fallback to %%any"); } else { plog("# default route not known: %s=%s", name, value); goto err; } } else if (streq(value, "%any") || streq(value, "%any4")) { anyaddr(conn->addr_family, &end->addr); } else if (streq(value, "%any6")) { conn->addr_family = AF_INET6; anyaddr(conn->addr_family, &end->addr); } else if (streq(value, "%group")) { ip_address any; conn->policy |= POLICY_GROUP | POLICY_TUNNEL; anyaddr(conn->addr_family, &end->addr); anyaddr(conn->tunnel_addr_family, &any); end->has_client = TRUE; } else { /* check for allow_any prefix */ if (value[0] == '%') { end->allow_any = TRUE; value++; } conn->addr_family = ip_version(value); ugh = ttoaddr(value, 0, conn->addr_family, &end->addr); if (ugh != NULL) { plog("# bad addr: %s=%s [%s]", name, value, ugh); if (streq(ugh, "does not look numeric and name lookup failed")) { end->dns_failed = TRUE; anyaddr(conn->addr_family, &end->addr); } else { goto err; } } } break; case KW_NEXTHOP: if (streq(value, "%defaultroute")) { if (cfg->defaultroute.defined) { end->nexthop = cfg->defaultroute.nexthop; } else { plog("# default route not known: %s=%s", name, value); goto err; } } else if (streq(value, "%direct")) { ugh = anyaddr(conn->addr_family, &end->nexthop); } else { conn->addr_family = ip_version(value); ugh = ttoaddr(value, 0, conn->addr_family, &end->nexthop); } if (ugh != NULL) { plog("# bad addr: %s=%s [%s]", name, value, ugh); goto err; } break; case KW_SUBNETWITHIN: { ip_subnet net; end->has_client = TRUE; end->has_client_wildcard = TRUE; conn->tunnel_addr_family = ip_version(value); ugh = ttosubnet(value, 0, ip_version(value), &net); if (ugh != NULL) { plog("# bad subnet: %s=%s [%s]", name, value, ugh); goto err; } end->subnet = clone_str(value); break; } case KW_PROTOPORT: ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &has_port_wildcard); end->has_port_wildcard = has_port_wildcard; break; case KW_NATIP: if (end->sourceip) { plog("# natip and sourceip cannot be defined at the same time"); goto err; } if (streq(value, "%defaultroute")) { char buf[64]; if (cfg->defaultroute.defined) { addrtot(&cfg->defaultroute.addr, 0, buf, sizeof(buf)); end->sourceip = clone_str(buf); } else { plog("# default route not known: %s=%s", name, value); goto err; } } else { ip_address addr; conn->tunnel_addr_family = ip_version(value); ugh = ttoaddr(value, 0, conn->tunnel_addr_family, &addr); if (ugh != NULL) { plog("# bad addr: %s=%s [%s]", name, value, ugh); goto err; } end->sourceip = clone_str(value); } end->has_natip = TRUE; conn->policy |= POLICY_TUNNEL; break; default: break; } return; err: plog(" bad argument value in conn '%s'", conn_name); cfg->err++; }
/** * Validate that yes in fact we are one side of the tunnel * * The function checks that IP addresses are valid, nexthops are * present (if needed) as well as policies, and sets the leftID * from the left= if it isn't set. * * @param conn_st a connection definition * @param end a connection end * @param left boolean (are we 'left'? 1 = yes, 0 = no) * @param perr pointer to char containing error value * @return bool TRUE if failed */ static bool validate_end(struct starter_conn *conn_st , struct starter_end *end , bool left , bool resolvip UNUSED , err_t *perr) { err_t er = NULL; char *err_str = NULL; const char *leftright=(left ? "left" : "right"); int family = conn_st->options[KBF_CONNADDRFAMILY]; bool err = FALSE; #define ERR_FOUND(args...) do { err += error_append(&err_str, ##args); } while(0) if(!end->options_set[KNCF_IP]) { conn_st->state = STATE_INCOMPLETE; } end->addrtype=end->options[KNCF_IP]; end->addr_family = family; /* validate the KSCF_IP/KNCF_IP */ switch(end->addrtype) { case KH_ANY: anyaddr(family, &(end->addr)); break; case KH_IFACE: /* generally, this doesn't show up at this stage */ break; case KH_IPADDR: /* right=/left= */ assert(end->strings[KSCF_IP] != NULL); if (end->strings[KSCF_IP][0]=='%') { if (end->iface) pfree(end->iface); end->iface = clone_str(end->strings[KSCF_IP] + 1, "KH_IPADDR end->iface"); if (starter_iface_find(end->iface, family, &(end->addr), &(end->nexthop)) == -1) { conn_st->state = STATE_INVALID; } /* not numeric, so set the type to the iface type */ end->addrtype = KH_IFACE; break; } er = ttoaddr_num(end->strings[KNCF_IP], 0, family, &(end->addr)); if(er) { /* not numeric, so set the type to the string type */ end->addrtype = KH_IPHOSTNAME; } if(end->id == NULL) { char idbuf[ADDRTOT_BUF]; addrtot(&end->addr, 0, idbuf, sizeof(idbuf)); end->id= clone_str(idbuf, "end id"); } break; case KH_OPPO: conn_st->policy |= POLICY_OPPO; break; case KH_OPPOGROUP: conn_st->policy |= POLICY_OPPO|POLICY_GROUP; break; case KH_GROUP: conn_st->policy |= POLICY_GROUP; break; case KH_IPHOSTNAME: /* XXX */ break; case KH_DEFAULTROUTE: break; case KH_NOTSET: break; } /* validate the KSCF_SUBNET */ if(end->strings_set[KSCF_SUBNET]) { char *value = end->strings[KSCF_SUBNET]; if ( ((strlen(value)>=6) && (strncmp(value,"vhost:",6)==0)) || ((strlen(value)>=5) && (strncmp(value,"vnet:",5)==0)) ) { er = NULL; end->virt = clone_str(value, "end->virt"); } else { end->has_client = TRUE; er = ttosubnet(value, 0, 0, &(end->subnet)); } if (er) ERR_FOUND("bad subnet %ssubnet=%s [%s] family=%s", leftright, value, er, family2str(family)); } /* set nexthop address to something consistent, by default */ anyaddr(family, &end->nexthop); anyaddr(addrtypeof(&end->addr), &end->nexthop); /* validate the KSCF_NEXTHOP */ if(end->strings_set[KSCF_NEXTHOP]) { char *value = end->strings[KSCF_NEXTHOP]; if(strcasecmp(value, "%defaultroute")==0) { end->nexttype=KH_DEFAULTROUTE; } else { if (tnatoaddr(value, strlen(value), AF_INET, &(end->nexthop)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->nexthop)) != NULL) { er = ttoaddr(value, 0, family, &(end->nexthop)); if (er) ERR_FOUND("bad addr %snexthop=%s [%s]", leftright, value, er); } end->nexttype = KH_IPADDR; } } else { if (end->addrtype == KH_DEFAULTROUTE) { end->nexttype = KH_DEFAULTROUTE; } anyaddr(family, &end->nexthop); } /* validate the KSCF_ID */ if(end->strings_set[KSCF_ID]) { char *value = end->strings[KSCF_ID]; pfreeany(end->id); end->id = clone_str(value, "end->id"); } if(end->options_set[KSCF_RSAKEY1]) { end->rsakey1_type = end->options[KSCF_RSAKEY1]; end->rsakey2_type = end->options[KSCF_RSAKEY2]; switch(end->rsakey1_type) { case PUBKEY_DNS: case PUBKEY_DNSONDEMAND: end->key_from_DNS_on_demand = TRUE; break; default: end->key_from_DNS_on_demand = FALSE; /* validate the KSCF_RSAKEY1/RSAKEY2 */ if(end->strings[KSCF_RSAKEY1] != NULL) { char *value = end->strings[KSCF_RSAKEY1]; pfreeany(end->rsakey1); end->rsakey1 = (unsigned char *)clone_str(value,"end->rsakey1"); } if(end->strings[KSCF_RSAKEY2] != NULL) { char *value = end->strings[KSCF_RSAKEY2]; pfreeany(end->rsakey2); end->rsakey2 = (unsigned char *)clone_str(value,"end->rsakey2"); } } } /* validate the KSCF_SOURCEIP, if any, and if set, * set the subnet to same value, if not set. */ if(end->strings_set[KSCF_SOURCEIP]) { char *value = end->strings[KSCF_SOURCEIP]; if (tnatoaddr(value, strlen(value), AF_INET, &(end->sourceip)) != NULL && tnatoaddr(value, strlen(value), AF_INET6, &(end->sourceip)) != NULL) { er = ttoaddr(value, 0, 0, &(end->sourceip)); if (er) ERR_FOUND("bad addr %ssourceip=%s [%s]", leftright, value, er); } else { er = tnatoaddr(value, 0, 0, &(end->sourceip)); if (er) ERR_FOUND("bad numerical addr %ssourceip=%s [%s]", leftright, value, er); } if(!end->has_client) { starter_log(LOG_LEVEL_INFO, "defaulting %ssubnet to %s\n", leftright, value); er = addrtosubnet(&end->sourceip, &end->subnet); if (er) ERR_FOUND("attempt to default %ssubnet from %s failed: %s", leftright, value, er); end->has_client = TRUE; end->has_client_wildcard = FALSE; } } /* copy certificate path name */ if(end->strings_set[KSCF_CERT]) { end->cert = clone_str(end->strings[KSCF_CERT], "KSCF_CERT"); } if(end->strings_set[KSCF_CA]) { end->ca = clone_str(end->strings[KSCF_CA], "KSCF_CA"); } if(end->strings_set[KSCF_UPDOWN]) { end->updown = clone_str(end->strings[KSCF_UPDOWN], "KSCF_UPDOWN"); } if(end->strings_set[KSCF_PROTOPORT]) { err_t ugh; char *value = end->strings[KSCF_PROTOPORT]; ugh = ttoprotoport(value, 0, &end->protocol, &end->port, &end->has_port_wildcard); if (ugh) ERR_FOUND("bad %sprotoport=%s [%s]", leftright, value, ugh); } if (end->options_set[KNCF_XAUTHSERVER] || end->options_set[KNCF_XAUTHCLIENT]) { conn_st->policy |= POLICY_XAUTH; } /* KSCF_SUBNETWITHIN --- not sure what to do with it. KSCF_ESPENCKEY --- todo (manual keying) KSCF_ESPAUTHKEY --- todo (manual keying) KSCF_SOURCEIP = 16, KSCF_MAX = 19 */ if(err) *perr = err_str; return err; # undef ERR_FOUND }