예제 #1
0
static bool init_load_conn(struct ub_ctx *dnsctx,
		   struct starter_config *cfg,
		   struct config_parsed *cfgp,
		   struct section_list *sconn,
		   bool defaultconn,
		   bool resolvip,
		   err_t *perr)
{
	bool connerr;
	struct starter_conn *conn;

	starter_log(LOG_LEVEL_DEBUG, "Loading conn %s", sconn->name);

	conn = alloc_add_conn(cfg, sconn->name);

	connerr = load_conn(dnsctx, conn, cfgp, sconn, TRUE,
			    defaultconn, resolvip, perr);

	if (connerr) {
		starter_log(LOG_LEVEL_INFO, "while loading '%s': %s",
			    sconn->name, *perr);
	} else {
		conn->state = STATE_LOADED;
	}
	return connerr;
}
예제 #2
0
int starter_stop_pluto (void)
{
	pid_t pid;
	int i;

	pid = _pluto_pid;
	if (pid) {
		_stop_requested = 1;
		if (starter_whack_shutdown()==0) {
			for (i=0; i<20; i++) {
				usleep(20000);
				if (_pluto_pid == 0) return 0;
			}
		}
		/**
		 * Be more and more aggressive
		 */
		for (i=0; (i<20) && ((pid=_pluto_pid)!=0); i++) {
			if (i<10) kill(pid, SIGTERM);
			else kill(pid, SIGKILL);
			usleep(20000);
		}
		if (_pluto_pid == 0) return 0;
		starter_log(LOG_LEVEL_ERR, "stater_stop_pluto(): can't stop pluto !!!");
		return -1;
	}
	else {
		starter_log(LOG_LEVEL_ERR,
			"stater_stop_pluto(): pluto is not started...");
	}
	return -1;
}
예제 #3
0
int init_load_conn(struct starter_config *cfg
		   , struct config_parsed *cfgp
		   , struct section_list *sconn
		   , bool alsoprocessing
		   , bool defaultconn
		   , bool resolvip
		   , err_t *perr)
{
    int connerr;
    struct starter_conn *conn;
    starter_log(LOG_LEVEL_DEBUG, "Loading conn %s", sconn->name);

    conn = alloc_add_conn(cfg, sconn->name, perr);
    if(conn == NULL) {
	return -1;
    }

    connerr = load_conn (cfg, conn, cfgp, sconn, TRUE,
			 defaultconn, resolvip, perr);

    if(connerr != 0) {
	starter_log(LOG_LEVEL_INFO, "while loading '%s': %s\n",
		    sconn->name, *perr);
    }
    if(connerr == 0)
    {
	conn->state = STATE_LOADED;
    }
    return connerr;
}
예제 #4
0
int starter_ifaces_load (char **ifaces, unsigned int omtu, int nat_t)
{
    char *tmp_phys, *phys;
    int n;
    char **i;
    int sock;
    int j, found;
    int ret = 0;

    starter_log(LOG_LEVEL_DEBUG, "starter_ifaces_load()");

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) return -1;

    for (j=0; j<N_IPSEC_IF; j++) {
        found = 0;
        for (i=ifaces; i && *i; i++) {
            if ((valid_str(*i, &n, &tmp_phys)) && (tmp_phys) &&
                    (n>=0) && (n<N_IPSEC_IF)) {
                if (n==j) {
                    if (found) {
                        starter_log(LOG_LEVEL_ERR,
                                    "ignoring duplicate entry for interface ipsec%d",
                                    j);
                    }
                    else {
                        found++;
                        phys = _find_physical_iface(sock, tmp_phys);
                        if (phys) {
                            ret += _iface_up (sock, &(_ipsec_if[n]), phys,
                                              omtu, nat_t);
                        }
                        else {
                            ret += _iface_down (sock, &(_ipsec_if[n]));
                        }
                    }
                }
            }
            else if (j==0) {
                /**
                 * Only log in the first loop
                 */
                starter_log(LOG_LEVEL_ERR, "ignoring invalid interface '%s'",
                            *i);
            }
        }
        if (!found)
            ret += _iface_down (sock, &(_ipsec_if[j]));
    }

    close(sock);
    return ret; /* = number of changes - 'whack --listen' if > 0 */
}
예제 #5
0
static int _iface_down (int sock, struct st_ipsec_if *iface)
{
    struct ifreq req;
    int ret = 0;

    iface->up = 0;

    strncpy(req.ifr_name, iface->name, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) {
        return ret;
    }

    if (req.ifr_flags & IFF_UP) {
        starter_log(LOG_LEVEL_INFO, "shutting down interface %s/%s",
                    iface->name, iface->phys);
        req.ifr_flags &= ~IFF_UP;
        ioctl(sock, SIOCSIFFLAGS, &req);
        ret = 1;
    }

    /* unset addr */
    memset(&req.ifr_addr, 0, sizeof(req.ifr_addr));
    req.ifr_addr.sa_family = AF_INET;
    ioctl(sock, SIOCSIFADDR, &req);

    /* tncfg --detach */
    ioctl(sock, IPSEC_DEL_DEV, &req);

    memset(iface->phys, 0, sizeof(iface->phys));

    return ret;
}
예제 #6
0
static void _sysflags (char *name, int value)
{
	if (starter_exec(
		"echo %d >%s/%s 2>/dev/null", value?1:0, PROC_SYSFLAGS, name
		)!=0) {
		starter_log(LOG_LEVEL_ERR, "can't set sysflag %s to %d", name,
			value ? 1 : 0);
	}
}
예제 #7
0
void starter_pluto_sigchild (pid_t pid)
{
	if (pid == _pluto_pid) {
		_pluto_pid = 0;
		if (!_stop_requested) {
			starter_log(LOG_LEVEL_ERR,
				"pluto has died -- restart scheduled (%dsec)",
				PLUTO_RESTART_DELAY);
			alarm(PLUTO_RESTART_DELAY);   // restart in 5 sec
		}
		unlink(PID_FILE);
	}
}
예제 #8
0
void starter_use_log(bool debug, bool console, bool mysyslog)
{
	log_debugging = debug;
	log_to_console = console;
	if (mysyslog != log_to_syslog) {
		if (mysyslog)
			openlog("ipsec_starter", LOG_PID, LOG_USER);
		else
			closelog();
		log_to_syslog = mysyslog;
	}
	if (log_debugging)
		starter_log(LOG_LEVEL_ERR, "debugging mode enabled");
}
예제 #9
0
int starter_exec (const char *fmt, ...)
{
	va_list args;
	static char buff[BUFF_SIZE];
	int r;

	va_start (args, fmt);
	vsnprintf(buff, BUFF_SIZE-1, fmt, args);
	buff[BUFF_SIZE-1] = '\0';
	va_end(args);
	
	if(showonly)
	{
	    starter_log(LOG_LEVEL_INFO, "showonly: invoking %s", buff);
	    r = 0;
	}
	else
	{
	    r = system(buff);
	    starter_log(LOG_LEVEL_DEBUG, "starter_exec(%s) = %d", buff, r);
	} 
	return r;
}
예제 #10
0
int starter_klips_init (void)
{
	struct stat stb;

	if (stat(PROC_IPSECVERSION,&stb)!=0) {
		if (stat(PROC_MODULES,&stb)==0) {
			unsetenv("MODPATH");
			unsetenv("MODULECONF");
			system("depmod -a >/dev/null 2>&1 && modprobe ipsec");
		}
		if (stat(PROC_IPSECVERSION,&stb)==0) {
			_klips_module_loaded = 1;
		}
		else {
			starter_log(LOG_LEVEL_ERR, "kernel appears to lack KLIPS");
			return 1;
		}
	}

	starter_klips_clear();

	return 0;
}
예제 #11
0
static bool load_conn(struct ub_ctx *dnsctx,
		     struct starter_conn *conn,
		     struct config_parsed *cfgp,
		     struct section_list *sl,
		     bool alsoprocessing,
		     bool defaultconn,
		     bool resolvip,
		     err_t *perr)
{
	bool err = FALSE;

	err |= load_conn_basic(conn, sl,
			       defaultconn ? k_default : k_set, perr);

	move_comment_list(&conn->comments, &sl->comments);

	if (err)
		return err;

	if (conn->strings[KSF_ALSO] != NULL &&
	    !alsoprocessing) {
		starter_log(LOG_LEVEL_INFO,
			    "also= is not valid in section '%s'",
			    sl->name);
		return TRUE;	/* error */
	}

	/* now, process the also's */
	if (conn->alsos)
		FREE_LIST(conn->alsos);
	conn->alsos = new_list(conn->strings[KSF_ALSO]);

	if (alsoprocessing && conn->alsos != NULL) {
		struct section_list *sl1;
		/* note: for the duration of this loop body
		 * conn->alsos is migrated to local variable alsos.
		 */
		char **alsos = conn->alsos;
		int alsosize;
		int alsoplace;

		conn->alsos = NULL;

		/* reset all of the "beenhere" flags */
		for (sl1 = cfgp->sections.tqh_first; sl1 != NULL;
		     sl1 = sl1->link.tqe_next)
			sl1->beenhere = FALSE;
		sl->beenhere = TRUE;

		/* count them */
		for (alsosize = 0; alsos[alsosize] != NULL; alsosize++)
			;

		alsoplace = 0;
		while (alsoplace < alsosize && alsos[alsoplace] != NULL &&
		       alsoplace < ALSO_LIMIT) {
			/*
			 * for each also= listed, go find this section's keyword list, and
			 * load it as well. This may extend the also= list (and the end),
			 * which we handle by zeroing the also list, and adding to it after
			 * checking for duplicates.
			 */
			for (sl1 = cfgp->sections.tqh_first;
			     sl1 != NULL &&
			     !streq(alsos[alsoplace], sl1->name);
			     sl1 = sl1->link.tqe_next)
				;

			starter_log(LOG_LEVEL_DEBUG,
				    "\twhile loading conn '%s' also including '%s'",
				    conn->name, alsos[alsoplace]);

			/*
			 * if we found something that matches by name, and we haven't be
			 * there, then process it.
			 */
			if (sl1 && !sl1->beenhere) {
				conn->strings_set[KSF_ALSO] = FALSE;
				pfreeany(conn->strings[KSF_ALSO]);
				conn->strings[KSF_ALSO] = NULL;
				sl1->beenhere = TRUE;

				/* translate things, but do not replace earlier settings!*/
				err |= translate_conn(conn, sl1, k_set, perr);

				if (conn->strings[KSF_ALSO] != NULL) {
					/* now, check out the KSF_ALSO, and extend list if we need to */
					char **newalsos = new_list(
						conn->strings[KSF_ALSO]);

					if (newalsos != NULL) {
						char **ra;
						int newalsoplace;

						/* count them */
						for (newalsoplace = 0;
						     newalsos[newalsoplace] !=
						     NULL;
						     newalsoplace++)
							;

						/* extend conn->alss */
						ra = alloc_bytes((alsosize +
							newalsoplace + 1) *
							sizeof(char *),
							"conn->alsos");
						memcpy(ra, alsos, alsosize * sizeof(char *));
						pfree(alsos);
						alsos = ra;
						for (newalsoplace = 0;
						     newalsos[newalsoplace] !=
						     NULL;
						     newalsoplace++) {
							assert(conn != NULL);
							assert(conn->name !=
								NULL);
							starter_log(
								LOG_LEVEL_DEBUG,
								"\twhile processing section '%s' added also=%s",
								sl1->name,
								newalsos[newalsoplace]);

							alsos[alsosize++] =
								clone_str(newalsos[newalsoplace],
									"alsos");
						}
						alsos[alsosize] = NULL;
					}

					FREE_LIST(newalsos);
				}
			}
			alsoplace++;
		}

		/* migrate alsos back to conn->alsos */
		conn->alsos = alsos;

		if (alsoplace >= ALSO_LIMIT) {
			starter_log(LOG_LEVEL_INFO,
				    "while loading conn '%s', too many also= used at section %s. Limit is %d",
				    conn->name,
				    alsos[alsoplace],
				    ALSO_LIMIT);
			return TRUE;	/* error */
		}
	}

#ifdef PARSER_TYPE_DEBUG
	/* translate strings/numbers into conn items */
	starter_log(LOG_LEVEL_DEBUG,
		    "#checking options_set[KBF_TYPE,%d]=%d %d",
		    KBF_TYPE,
		    conn->options_set[KBF_TYPE], conn->options[KBF_TYPE]);
#endif

	if (conn->options_set[KBF_TYPE]) {
		switch ((enum keyword_satype)conn->options[KBF_TYPE]) {
		case KS_TUNNEL:
			conn->policy |= POLICY_TUNNEL;
			conn->policy &= ~POLICY_SHUNT_MASK;
			break;

		case KS_TRANSPORT:
			conn->policy &= ~POLICY_TUNNEL;
			conn->policy &= ~POLICY_SHUNT_MASK;
			break;

		case KS_PASSTHROUGH:
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_PASS;
			break;

		case KS_DROP:
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_DROP;
			break;

		case KS_REJECT:
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_REJECT;
			break;
		}
	}

	if (conn->options_set[KBF_FAILURESHUNT]) {
		conn->policy &= ~POLICY_FAIL_MASK;
		switch(conn->options[KBF_FAILURESHUNT]) {
		case KFS_FAIL_NONE:
			conn->policy |= POLICY_FAIL_NONE;
			break;
		case KFS_FAIL_PASS:
			conn->policy |= POLICY_FAIL_PASS;
			break;
		case KFS_FAIL_DROP:
			conn->policy |= POLICY_FAIL_DROP;
			break;
		case KFS_FAIL_REJECT:
			conn->policy |= POLICY_FAIL_REJECT;
			break;
		}
	}

	if (conn->options_set[KBF_NEGOTIATIONSHUNT]) {
		switch(conn->options[KBF_NEGOTIATIONSHUNT]) {
		case KNS_FAIL_PASS:
			conn->policy |= POLICY_NEGO_PASS;
			break;
		case KNS_FAIL_DROP:
			conn->policy &= ~POLICY_NEGO_PASS;
			break;
		}
	}

	KW_POLICY_FLAG(KBF_COMPRESS, POLICY_COMPRESS);
	KW_POLICY_FLAG(KBF_PFS,  POLICY_PFS);

	/* reset authby flags */
	if (conn->options_set[KBF_AUTHBY]) {
		conn->policy &= ~(POLICY_ID_AUTH_MASK);

#ifdef FIPS_CHECK
		if (libreswan_fipsmode()) {
			if (LIN(POLICY_PSK, conn->options[KBF_AUTHBY])) {
				starter_log(LOG_LEVEL_INFO,
					    "while loading conn '%s', PSK not allowed in FIPS mode with NSS",
					    conn->name);
				return TRUE;	/* error */
			}
		}
#endif

		conn->policy |= conn->options[KBF_AUTHBY];

#ifdef STARTER_POLICY_DEBUG
		starter_log(LOG_LEVEL_DEBUG,
			    "%s: setting conn->policy=%08x (%08x)",
			    conn->name,
			    (unsigned int)conn->policy,
			    conn->options[KBF_AUTHBY]);
#endif
	}

	KW_POLICY_NEGATIVE_FLAG(KBF_IKEPAD, POLICY_NO_IKEPAD);

	KW_POLICY_NEGATIVE_FLAG(KBF_REKEY, POLICY_DONT_REKEY);

	KW_POLICY_FLAG(KBF_AGGRMODE, POLICY_AGGRESSIVE);

	KW_POLICY_FLAG(KBF_MODECONFIGPULL, POLICY_MODECFG_PULL);

	KW_POLICY_FLAG(KBF_OVERLAPIP, POLICY_OVERLAPIP);

	KW_POLICY_FLAG(KBF_IKEv2_ALLOW_NARROWING,
		       POLICY_IKEV2_ALLOW_NARROWING);

	KW_POLICY_FLAG(KBF_IKEv2_PAM_AUTHORIZE,
		       POLICY_IKEV2_PAM_AUTHORIZE);

	if (conn->strings_set[KSF_ESP])
		conn->esp = clone_str(conn->strings[KSF_ESP],"KSF_ESP");

#ifdef HAVE_LABELED_IPSEC
	if (conn->strings_set[KSF_POLICY_LABEL])
		conn->policy_label = clone_str(conn->strings[KSF_POLICY_LABEL],"KSF_POLICY_LABEL");
	if (conn->policy_label != NULL)
		starter_log(LOG_LEVEL_DEBUG, "connection's  policy label: %s",
				conn->policy_label);
#endif

	if (conn->strings_set[KSF_IKE])
		conn->ike = clone_str(conn->strings[KSF_IKE],"KSF_IKE");

	if (conn->strings_set[KSF_MODECFGDNS1]) {
		conn->modecfg_dns1 = clone_str(conn->strings[KSF_MODECFGDNS1],"KSF_MODECFGDNS1");
	}
	if (conn->strings_set[KSF_MODECFGDNS2]) {
		conn->modecfg_dns2 = clone_str(conn->strings[KSF_MODECFGDNS2], "KSF_MODECFGDNS2");
	}
	if (conn->strings_set[KSF_MODECFGDOMAIN]) {
		conn->modecfg_domain = clone_str(conn->strings[KSF_MODECFGDOMAIN],"KSF_MODECFGDOMAIN");
	}
	if (conn->strings_set[KSF_MODECFGBANNER]) {
		conn->modecfg_banner = clone_str(conn->strings[KSF_MODECFGBANNER],"KSF_MODECFGBANNER");
	}

	if (conn->strings_set[KSF_CONNALIAS])
		conn->connalias = clone_str(conn->strings[KSF_CONNALIAS],"KSF_CONNALIAS");

	if (conn->options_set[KBF_PHASE2]) {
		conn->policy &= ~(POLICY_AUTHENTICATE | POLICY_ENCRYPT);
		conn->policy |= conn->options[KBF_PHASE2];
	}

	if (conn->options_set[KBF_IKEv2]) {
		lset_t policy = LEMPTY;

		switch (conn->options[KBF_IKEv2]) {
		case fo_never:
			policy = POLICY_IKEV1_ALLOW;
			break;

		case fo_permit:
			/* this is the default for now */
			policy = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW;
			break;

		case fo_propose:
			policy = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
			break;

		case fo_insist:
			policy =                      POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
			break;
		}
		conn->policy = (conn->policy & ~POLICY_IKEV2_MASK) | policy;
	}

	if (conn->options_set[KBF_IKE_FRAG]) {
		switch (conn->options[KBF_IKE_FRAG]) {
		case ynf_no:
			conn->policy &= ~POLICY_IKE_FRAG_ALLOW;
			conn->policy &= ~POLICY_IKE_FRAG_FORCE;
			break;

		case ynf_yes:
			/* this is the default */
			conn->policy |= POLICY_IKE_FRAG_ALLOW;
			break;

		case ynf_force:
			conn->policy |= POLICY_IKE_FRAG_ALLOW |
					POLICY_IKE_FRAG_FORCE;
			break;
		}
	}

	if (conn->options_set[KBF_SAREFTRACK]) {
		switch (conn->options[KBF_SAREFTRACK]) {
		case sat_yes:
			/* this is the default */
			conn->policy |= POLICY_SAREF_TRACK;
			break;

		case sat_conntrack:
			conn->policy |= POLICY_SAREF_TRACK |
					POLICY_SAREF_TRACK_CONNTRACK;
			break;

		case sat_no:
			conn->policy &= ~POLICY_SAREF_TRACK;
			conn->policy &= ~POLICY_SAREF_TRACK_CONNTRACK;
			break;
		}
	}

	err |= validate_end(dnsctx, conn, &conn->left,  "left",  resolvip, perr);
	err |= validate_end(dnsctx, conn, &conn->right, "right", resolvip, perr);
	/*
	 * TODO:
	 * verify both ends are using the same inet family, if one end
	 * is "%any" or "%defaultroute", then perhaps adjust it.
	 * ensource this for left,leftnexthop,right,rightnexthop
	 * Ideally, phase out connaddrfamily= which now wrongly assumes
	 * left,leftnextop,leftsubnet are the same inet family
	 * Currently, these tests are implicitely done, and wrongly
	 * in case of 6in4 and 4in6 tunnels
	 */

	if (conn->options_set[KBF_AUTO])
		conn->desired_state = conn->options[KBF_AUTO];

	return err;
}
예제 #12
0
/**
 * Take keywords from ipsec.conf syntax and load into a conn struct
 *
 *
 * @param conn a connection definition
 * @param sl a section_list
 * @param assigned_value is set to either k_set, or k_default.
 *        k_default is used when we are loading a conn that should be
 *        considered to be a "default" value, and that replacing this
 *        value is considered acceptable.
 * @return bool TRUE if unsuccessfull
 */
static bool translate_conn(struct starter_conn *conn,
		    struct section_list *sl,
		    enum keyword_set assigned_value,
		    err_t *error)
{
	bool err = FALSE;
	struct kw_list *kw;

	for (kw = sl->kw; kw; kw = kw->next) {
		ksf *the_strings = &conn->strings;
		str_set *set_strings = &conn->strings_set;
		knf *the_options = &conn->options;
		int_set *set_options = &conn->options_set;
		unsigned int field;

		if ((kw->keyword.keydef->validity & kv_conn) == 0) {
			/* this isn't valid in a conn! */
			*error = (const char *)tmp_err;

			snprintf(tmp_err, sizeof(tmp_err),
				 "keyword '%s' is not valid in a conn (%s)\n",
				 kw->keyword.keydef->keyname, sl->name);
			starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
			continue;
		}

		if (kw->keyword.keydef->validity & kv_leftright) {
			if (kw->keyword.keyleft) {
				the_strings = &conn->left.strings;
				the_options = &conn->left.options;
				set_strings = &conn->left.strings_set;
				set_options = &conn->left.options_set;
			} else {
				the_strings = &conn->right.strings;
				the_options = &conn->right.options;
				set_strings = &conn->right.strings_set;
				set_options = &conn->right.options_set;
			}
		}

		field = kw->keyword.keydef->field;

#ifdef PARSER_TYPE_DEBUG
		starter_log(LOG_LEVEL_DEBUG, "#analyzing %s[%d] kwtype=%d",
			    kw->keyword.keydef->keyname, field,
			    kw->keyword.keydef->type);
#endif

		assert(kw->keyword.keydef != NULL);
		switch (kw->keyword.keydef->type) {
		case kt_string:
		case kt_filename:
		case kt_dirname:
		case kt_bitstring:
		case kt_ipaddr:
		case kt_range:
		case kt_subnet:
		case kt_idtype:
			/* all treated as strings for now */
			assert(kw->keyword.keydef->field < KEY_STRINGS_MAX);
			if ((*set_strings)[field] == k_set) {
				*error = tmp_err;

				snprintf(tmp_err, sizeof(tmp_err),
					 "duplicate key '%s' in conn %s while processing def %s",
					 kw->keyword.keydef->keyname,
					 conn->name,
					 sl->name);

				starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
				if (kw->keyword.string == NULL ||
				    (*the_strings)[field] == NULL ||
				    !streq(kw->keyword.string,
					   (*the_strings)[field])) {
					err = TRUE;
					break;
				}
			}
			pfreeany((*the_strings)[field]);

			if (kw->string == NULL) {
				*error = tmp_err;

				snprintf(tmp_err, sizeof(tmp_err),
					 "Invalid %s value",
					 kw->keyword.keydef->keyname);
				err = TRUE;
				break;
			}

			(*the_strings)[field] = clone_str(kw->string,"kt_idtype kw->string");
			(*set_strings)[field] = assigned_value;
			break;

		case kt_appendstring:
		case kt_appendlist:
			/* implicitly, this field can have multiple values */
			assert(kw->keyword.keydef->field < KEY_STRINGS_MAX);
			if ((*the_strings)[field] == NULL) {
				(*the_strings)[field] = clone_str(kw->string, "kt_appendlist kw->string");
			} else {
				char *s = (*the_strings)[field];
				size_t old_len = strlen(s);	/* excludes '\0' */
				size_t new_len = strlen(kw->string);
				char *n;

				n = alloc_bytes(old_len + 1 + new_len + 1, "kt_appendlist");
				memcpy(n, s, old_len);
				n[old_len] = ' ';
				memcpy(n + old_len + 1, kw->string, new_len + 1);	/* includes '\0' */
				(*the_strings)[field] = n;
				pfree(s);
			}
			(*set_strings)[field] = TRUE;
			break;

		case kt_rsakey:
		case kt_loose_enum:
			assert(field < KEY_STRINGS_MAX);
			assert(field < KEY_NUMERIC_MAX);

			if ((*set_options)[field] == k_set) {
				*error = tmp_err;
				snprintf(tmp_err, sizeof(tmp_err),
					 "duplicate key '%s' in conn %s while processing def %s",
					 kw->keyword.keydef->keyname,
					 conn->name,
					 sl->name);

				starter_log(LOG_LEVEL_INFO, "%s", tmp_err);

				/* only fatal if we try to change values */
				if ((*the_options)[field] != (int)kw->number ||
				    !((*the_options)[field] ==
				      LOOSE_ENUM_OTHER &&
				      kw->number == LOOSE_ENUM_OTHER &&
				      kw->keyword.string != NULL &&
				      (*the_strings)[field] != NULL &&
				      streq(kw->keyword.string,
					     (*the_strings)[field]))) {
					err = TRUE;
					break;
				}
			}

			(*the_options)[field] = kw->number;
			if (kw->number == LOOSE_ENUM_OTHER) {
				assert(kw->keyword.string != NULL);
				pfreeany((*the_strings)[field]);
				(*the_strings)[field] = clone_str(
					kw->keyword.string, "kt_loose_enum kw->keyword.string");
			}
			(*set_options)[field] = assigned_value;
			break;

		case kt_list:
		case kt_bool:
		case kt_invertbool:
		case kt_enum:
		case kt_number:
		case kt_time:
		case kt_percent:
			/* all treated as a number for now */
			assert(field < KEY_NUMERIC_MAX);

			if ((*set_options)[field] == k_set) {
				*error = tmp_err;
				snprintf(tmp_err, sizeof(tmp_err),
					 "duplicate key '%s' in conn %s while processing def %s",
					 kw->keyword.keydef->keyname,
					 conn->name,
					 sl->name);
				starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
				if ((*the_options)[field] != (int)kw->number) {
					err = TRUE;
					break;
				}
			}

#if 0
			starter_log(LOG_LEVEL_DEBUG, "#setting %s[%d]=%u",
				    kw->keyword.keydef->keyname, field,
				    kw->number);
#endif
			(*the_options)[field] = kw->number;
			(*set_options)[field] = assigned_value;
			break;

		case kt_comment:
			break;
		case kt_obsolete:
			starter_log(LOG_LEVEL_INFO,
				    "Warning: obsolete keyword '%s' ignored",
				    kw->keyword.keydef->keyname);
			break;
		case kt_obsolete_quiet:
			starter_log(LOG_LEVEL_DEBUG,
				    "Warning: obsolete keyword '%s' ignored",
				    kw->keyword.keydef->keyname);
			break;
		}
	}
	return err;
}
예제 #13
0
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
}
예제 #14
0
/**
 * Load a parsed config
 *
 * @param cfg starter_config structure
 * @param cfgp config_parsed (ie: valid) struct
 * @param perr pointer to store errors in
 * @return bool TRUE if unsuccessfull
 */
static bool load_setup(struct starter_config *cfg,
		      struct config_parsed *cfgp)
{
	bool err = FALSE;
	struct kw_list *kw;

	for (kw = cfgp->config_setup; kw; kw = kw->next) {

		/**
		 * the parser already made sure that only config keywords were used,
		 * but we double check!
		 */
		assert(kw->keyword.keydef->validity & kv_config);

		switch (kw->keyword.keydef->type) {
		case kt_string:
		case kt_filename:
		case kt_dirname:
		case kt_loose_enum:
			/* all treated as strings for now */
			assert(kw->keyword.keydef->field <
			       sizeof(cfg->setup.strings));
			pfreeany(cfg->setup.strings[kw->keyword.keydef->
							field]);
			cfg->setup.strings[kw->keyword.keydef->field] =
				clone_str(kw->string, "kt_loose_enum kw->string");
			cfg->setup.strings_set[kw->keyword.keydef->field] =
				TRUE;
			break;

		case kt_list:
		case kt_bool:
		case kt_invertbool:
		case kt_enum:
		case kt_number:
		case kt_time:
		case kt_percent:
			/* all treated as a number for now */
			assert(kw->keyword.keydef->field <
			       sizeof(cfg->setup.options));
			cfg->setup.options[kw->keyword.keydef->field] =
				kw->number;
			cfg->setup.options_set[kw->keyword.keydef->field] =
				TRUE;
			break;

		case kt_bitstring:
		case kt_rsakey:
		case kt_ipaddr:
		case kt_subnet:
		case kt_range:
		case kt_idtype:
			err = TRUE;
			break;

		case kt_comment:
			break;

		case kt_obsolete:
			starter_log(LOG_LEVEL_INFO,
				    "Warning: ignored obsolete keyword '%s'",
				    kw->keyword.keydef->keyname);
			break;
		case kt_obsolete_quiet:
			starter_log(LOG_LEVEL_DEBUG,
				    "Warning: ignored obsolete keyword '%s'",
				    kw->keyword.keydef->keyname);
			break;
		default:
		    /* NEVER HAPPENS */
		    break;
		}
	}

	/* now process some things with specific values */

	/* interfaces has to be chopped up */
	if (cfg->setup.interfaces)
		FREE_LIST(cfg->setup.interfaces);
	cfg->setup.interfaces = new_list(cfg->setup.strings[KSF_INTERFACES]);

	return err;
}
예제 #15
0
struct starter_config *confread_load(const char *file,
				     err_t *perr,
				     bool resolvip,
				     const char *ctlbase,
				     bool setuponly)
{
	struct starter_config *cfg = NULL;
	struct config_parsed *cfgp;
	struct section_list *sconn;
	bool err = FALSE;
	bool connerr;

#ifdef DNSSEC
	struct ub_ctx *dnsctx =  ub_ctx_create();
	unbound_init(dnsctx);
#else
	struct ub_ctx *dnsctx = NULL;
#endif
	/**
	 * Load file
	 */
	cfgp = parser_load_conf(file, perr);
	if (!cfgp)
		return NULL;

	cfg = (struct starter_config *)alloc_bytes(sizeof(struct starter_config),"starter_config cfg");

	/**
	 * Set default values
	 */
	ipsecconf_default_values(cfg);

	if (ctlbase) {
		pfree(cfg->ctlbase);
		cfg->ctlbase = clone_str(ctlbase, "control socket");
	}

	/**
	 * Load setup
	 */
	err |= load_setup(cfg, cfgp);

	if (err) {
		parser_free_conf(cfgp);
		confread_free(cfg);
		return NULL;
	}

	if (!setuponly) {
		/**
		 * Find %default and %oedefault conn
		 *
		 */
		for (sconn = cfgp->sections.tqh_first; (!err) && sconn != NULL;
		     sconn = sconn->link.tqe_next) {
			if (streq(sconn->name, "%default")) {
				starter_log(LOG_LEVEL_DEBUG,
					    "Loading default conn");
				err |= load_conn(dnsctx,
						 &cfg->conn_default,
						 cfgp, sconn, FALSE,
						/*default conn*/ TRUE,
						 resolvip, perr);
			}

			if (streq(sconn->name, "%oedefault")) {
				starter_log(LOG_LEVEL_DEBUG,
					    "Loading oedefault conn");
				err |= load_conn(dnsctx,
						 &cfg->conn_oedefault,
						 cfgp, sconn, FALSE,
						/*default conn*/ TRUE,
						 resolvip, perr);
				if (!err)
					cfg->got_oedefault = TRUE;
			}
		}

		/**
		 * Load other conns
		 */
		for (sconn = cfgp->sections.tqh_first; sconn != NULL;
		     sconn = sconn->link.tqe_next) {
			if (streq(sconn->name, "%default"))
				continue;
			if (streq(sconn->name, "%oedefault"))
				continue;

			connerr = init_load_conn(dnsctx, cfg, cfgp, sconn,
						 FALSE,
						 resolvip, perr);

#if 0	/* ??? the following condition can never be true */
			if (connerr == -1) {
				parser_free_conf(cfgp);
				confread_free(cfg);
				return NULL;
			}
#endif
			err |= connerr;
		}

		/* if we have OE on, then create any missing OE conns! */
		if (cfg->setup.options[KBF_OPPOENCRYPT]) {
			starter_log(LOG_LEVEL_DEBUG, "Enabling OE conns");
			add_any_oeconns(cfg, cfgp);
		}
	}

	parser_free_conf(cfgp);

	return cfg;
}
예제 #16
0
/**
 * Take keywords from ipsec.conf syntax and load into a conn struct
 *
 * @param conn a connection definition
 * @param sl a section_list
 * @param assigned_value is set to either k_set, or k_default.
 *        k_default is used when we are loading a conn that should be
 *        considered to be a "default" value, and that replacing this
 *        value is considered acceptable.
 * @return bool TRUE if unsuccessful
 */
static bool translate_conn(struct starter_conn *conn,
		    const struct section_list *sl,
		    enum keyword_set assigned_value,
		    err_t *error)
{
	/*
	 * tmp_err must be able to carry an error message back to our caller.
	 * Thus it must be static.
	 * Great discipline is required to make sure that at most one error
	 * message needs to persist.
	 */
	static char tmp_err[512];

	bool err = FALSE;
	const struct kw_list *kw;

	for (kw = sl->kw; kw; kw = kw->next) {
		ksf *the_strings = &conn->strings;
		str_set *set_strings = &conn->strings_set;
		knf *the_options = &conn->options;
		int_set *set_options = &conn->options_set;

		if ((kw->keyword.keydef->validity & kv_conn) == 0) {
			/* this isn't valid in a conn! */
			/* ??? pray nobody else wants to use tmp_err */
			*error = tmp_err;

			snprintf(tmp_err, sizeof(tmp_err),
				 "keyword '%s' is not valid in a conn (%s)\n",
				 kw->keyword.keydef->keyname, sl->name);
			starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
			continue;
		}

		if (kw->keyword.keydef->validity & kv_leftright) {
			struct starter_end *this = kw->keyword.keyleft ?
				&conn->left : &conn->right;

			the_strings = &this->strings;
			the_options = &this->options;
			set_strings = &this->strings_set;
			set_options = &this->options_set;
		}

		unsigned int field = kw->keyword.keydef->field;

		assert(kw->keyword.keydef != NULL);
		switch (kw->keyword.keydef->type) {
		case kt_string:
		case kt_filename:
		case kt_dirname:
		case kt_bitstring:
		case kt_ipaddr:
		case kt_range:
		case kt_subnet:
		case kt_idtype:
			/* all treated as strings for now */
			assert(kw->keyword.keydef->field < KEY_STRINGS_MAX);
			if ((*set_strings)[field] == k_set) {
				/* ??? pray nobody else wants to use tmp_err */
				*error = tmp_err;

				snprintf(tmp_err, sizeof(tmp_err),
					 "duplicate key '%s' in conn %s while processing def %s",
					 kw->keyword.keydef->keyname,
					 conn->name,
					 sl->name);

				starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
				if (kw->keyword.string == NULL ||
				    (*the_strings)[field] == NULL ||
				    !streq(kw->keyword.string,
					   (*the_strings)[field])) {
					err = TRUE;
					break;
				}
			}
			pfreeany((*the_strings)[field]);

			if (kw->string == NULL) {
				/* ??? pray nobody else wants to use tmp_err */
				*error = tmp_err;

				snprintf(tmp_err, sizeof(tmp_err),
					 "Invalid %s value",
					 kw->keyword.keydef->keyname);
				err = TRUE;
				break;
			}

			(*the_strings)[field] = clone_str(kw->string,"kt_idtype kw->string");
			(*set_strings)[field] = assigned_value;
			break;

		case kt_appendstring:
		case kt_appendlist:
			/* implicitly, this field can have multiple values */
			assert(kw->keyword.keydef->field < KEY_STRINGS_MAX);
			if ((*the_strings)[field] == NULL) {
				(*the_strings)[field] = clone_str(kw->string, "kt_appendlist kw->string");
			} else {
				char *s = (*the_strings)[field];
				size_t old_len = strlen(s);	/* excludes '\0' */
				size_t new_len = strlen(kw->string);
				char *n;

				n = alloc_bytes(old_len + 1 + new_len + 1, "kt_appendlist");
				memcpy(n, s, old_len);
				n[old_len] = ' ';
				memcpy(n + old_len + 1, kw->string, new_len + 1);	/* includes '\0' */
				(*the_strings)[field] = n;
				pfree(s);
			}
			(*set_strings)[field] = TRUE;
			break;

		case kt_rsakey:
		case kt_loose_enum:
			assert(field < KEY_STRINGS_MAX);
			assert(field < KEY_NUMERIC_MAX);

			if ((*set_options)[field] == k_set) {
				/* ??? pray nobody else wants to use tmp_err */
				*error = tmp_err;
				snprintf(tmp_err, sizeof(tmp_err),
					 "duplicate key '%s' in conn %s while processing def %s",
					 kw->keyword.keydef->keyname,
					 conn->name,
					 sl->name);

				starter_log(LOG_LEVEL_INFO, "%s", tmp_err);

				/* only fatal if we try to change values */
				if ((*the_options)[field] != (int)kw->number ||
				    !((*the_options)[field] ==
				      LOOSE_ENUM_OTHER &&
				      kw->number == LOOSE_ENUM_OTHER &&
				      kw->keyword.string != NULL &&
				      (*the_strings)[field] != NULL &&
				      streq(kw->keyword.string,
					     (*the_strings)[field]))) {
					err = TRUE;
					break;
				}
				/* ??? at this point, we have set *error but not err! */
			}

			(*the_options)[field] = kw->number;
			if (kw->number == LOOSE_ENUM_OTHER) {
				assert(kw->keyword.string != NULL);
				pfreeany((*the_strings)[field]);
				(*the_strings)[field] = clone_str(
					kw->keyword.string, "kt_loose_enum kw->keyword.string");
			}
			(*set_options)[field] = assigned_value;
			break;

		case kt_list:
		case kt_bool:
		case kt_invertbool:
		case kt_enum:
		case kt_number:
		case kt_time:
		case kt_percent:
			/* all treated as a number for now */
			assert(field < KEY_NUMERIC_MAX);

			if ((*set_options)[field] == k_set) {
				/* ??? pray nobody else wants to use tmp_err */
				*error = tmp_err;
				snprintf(tmp_err, sizeof(tmp_err),
					 "duplicate key '%s' in conn %s while processing def %s",
					 kw->keyword.keydef->keyname,
					 conn->name,
					 sl->name);
				starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
				if ((*the_options)[field] != (int)kw->number) {
					err = TRUE;
					break;
				}
				/* ??? at this point, we have set *error but not err! */
			}

#if 0
			starter_log(LOG_LEVEL_DEBUG, "#setting %s[%d]=%u",
				    kw->keyword.keydef->keyname, field,
				    kw->number);
#endif
			(*the_options)[field] = kw->number;
			(*set_options)[field] = assigned_value;
			break;

		case kt_comment:
			break;

		case kt_obsolete:
			starter_log(LOG_LEVEL_INFO,
				    "Warning: obsolete keyword '%s' ignored",
				    kw->keyword.keydef->keyname);
			break;

		case kt_obsolete_quiet:
			starter_log(LOG_LEVEL_DEBUG,
				    "Warning: obsolete keyword '%s' ignored",
				    kw->keyword.keydef->keyname);
			break;
		}
	}
	return err;
}
예제 #17
0
static int load_conn (struct starter_config *cfg
		      , struct starter_conn *conn
		      , struct config_parsed *cfgp
		      , struct section_list *sl
		      , bool alsoprocessing
		      , bool defaultconn
		      , bool resolvip
		      , err_t *perr)
{
    unsigned int err;
    err = 0;

    err += load_conn_basic(conn, sl, defaultconn ? k_default : k_set, perr);

    move_comment_list(&conn->comments, &sl->comments);

    if(err) return err;

    if(conn->strings[KSF_ALSO] != NULL
       && !alsoprocessing)
    {
	starter_log(LOG_LEVEL_INFO
		    , "also= is not valid in section '%s'"
		    , sl->name);
	return 1;
    }

    /* now, process the also's */
    if (conn->alsos) free_list(conn->alsos);
    conn->alsos = new_list(conn->strings[KSF_ALSO]);

    if(alsoprocessing && conn->alsos)
    {
        unsigned int alsosize;
        char **alsos;
        struct section_list *sl1;

	/* reset all of the "beenhere" flags: can not also= and alsoflip= the same conn, btw. */
	for(sl1 = cfgp->sections.tqh_first; sl1 != NULL; sl1 = sl1->link.tqe_next)
	{
	    sl1->beenhere = FALSE;
	}
	sl->beenhere = TRUE;

        /* count them */
        alsos = conn->alsos;
        conn->alsos = NULL;
        for(alsosize=0; alsos[alsosize]!=NULL; alsosize++);

        starter_log(LOG_LEVEL_DEBUG, "# conn %s processing alsos", conn->name);
        conn->alsos = process_alsos(cfg, conn, cfgp, alsos, alsosize, FALSE, perr);

        if(conn->strings[KSF_ALSOFLIP]) {
            alsos = new_list(conn->strings[KSF_ALSOFLIP]);
            for(alsosize=0; alsos[alsosize]!=NULL; alsosize++);

            starter_log(LOG_LEVEL_DEBUG, "# conn %s processing alsoflips", conn->name);
            conn->also_flips = process_alsos(cfg, conn, cfgp, alsos, alsosize, TRUE, perr);
        }
    }

#ifdef PARSER_TYPE_DEBUG
    /* translate strings/numbers into conn items */
    starter_log(LOG_LEVEL_DEBUG, "#checking options_set[KBF_TYPE,%d]=%d %d\n",
		KBF_TYPE,
		conn->options_set[KBF_TYPE], conn->options[KBF_TYPE]);
#endif

    if(conn->options_set[KBF_TYPE]) {
	switch((enum keyword_satype)conn->options[KBF_TYPE]) {
	case KS_TUNNEL:
	    conn->policy |= POLICY_TUNNEL;
	    conn->policy &= ~POLICY_SHUNT_MASK;
	    break;

	case KS_TRANSPORT:
	    conn->policy &= ~POLICY_TUNNEL;
	    conn->policy &= ~POLICY_SHUNT_MASK;
	    break;

	case KS_UDPENCAP:
	    /* no way to specify this yet! */
	    break;

	case KS_PASSTHROUGH:
	    conn->policy &= ~(POLICY_ENCRYPT|POLICY_AUTHENTICATE|POLICY_TUNNEL|POLICY_RSASIG);
	    conn->policy &= ~POLICY_SHUNT_MASK;
	    conn->policy |= POLICY_SHUNT_PASS;
	    break;

	case KS_DROP:
	    conn->policy &= ~(POLICY_ENCRYPT|POLICY_AUTHENTICATE|POLICY_TUNNEL|POLICY_RSASIG);
	    conn->policy &= ~POLICY_SHUNT_MASK;
	    conn->policy |= POLICY_SHUNT_DROP;
	    break;

	case KS_REJECT:
	    conn->policy &= ~(POLICY_ENCRYPT|POLICY_AUTHENTICATE|POLICY_TUNNEL|POLICY_RSASIG);
	    conn->policy &= ~POLICY_SHUNT_MASK;
	    conn->policy |= POLICY_SHUNT_REJECT;
	    break;
	}
    }

    KW_POLICY_FLAG(KBF_COMPRESS, POLICY_COMPRESS);
    KW_POLICY_FLAG(KBF_PFS,  POLICY_PFS);

    /* reset authby flags */
    if(conn->options_set[KBF_AUTHBY]) {
	conn->policy &= ~(POLICY_ID_AUTH_MASK);
	conn->policy |= conn->options[KBF_AUTHBY];

#if STARTER_POLICY_DEBUG
	starter_log(LOG_LEVEL_DEBUG,
		    "%s: setting conn->policy=%08x (%08x)\n",
		    conn->name,
		    (unsigned int)conn->policy,
		    conn->options[KBF_AUTHBY]);
#endif
    }

    KW_POLICY_NEGATIVE_FLAG(KBF_REKEY, POLICY_DONT_REKEY);

    KW_POLICY_FLAG(KBF_AGGRMODE, POLICY_AGGRESSIVE);

    KW_POLICY_FLAG(KBF_MODECONFIGPULL, POLICY_MODECFG_PULL);

    KW_POLICY_FLAG(KBF_OVERLAPIP, POLICY_OVERLAPIP);

    KW_POLICY_FLAG(KBF_IKEv2_ALLOW_NARROWING, POLICY_IKEV2_ALLOW_NARROWING);

    if(conn->strings_set[KSF_ESP]) {
        conn->esp = clone_str(conn->strings[KSF_ESP],"KSF_ESP");
    }

#ifdef HAVE_LABELED_IPSEC
    if(conn->strings_set[KSF_POLICY_LABEL]) {
        conn->policy_label = clone_str(conn->strings[KSF_POLICY_LABEL],"KSF_POLICY_LABEL");
    }
    starter_log(LOG_LEVEL_DEBUG,"connection's  policy label: %s", conn->policy_label);
#endif

#if 0
    if (conn->strings_set[KSF_MODECFGDNS1]) {
        conn->modecfg_dns1 = clone_str(conn->strings[KSF_MODECFGDNS1],"KSF_MODECFGDNS1");
    }
    if (conn->strings_set[KSF_MODECFGDNS2]) {
        conn->modecfg_dns2 = clone_str(conn->strings[KSF_MODECFGDNS2], "KSF_MODECFGDNS2");
    }
    if (conn->strings_set[KSF_MODECFGDOMAIN]) {
        conn->modecfg_domain = clone_str(conn->strings[KSF_MODECFGDOMAIN],"KSF_MODECFGDOMAIN");
    }
    if (conn->strings_set[KSF_MODECFGBANNER]) {
        conn->modecfg_banner = clone_str(conn->strings[KSF_MODECFGBANNER],"KSF_MODECFGBANNER");
    }
#endif

    if(conn->strings_set[KSF_IKE]) {
        conn->ike = clone_str(conn->strings[KSF_IKE],"KSF_IKE");
    }

    if(conn->strings_set[KSF_CONNALIAS]) {
        conn->connalias = clone_str(conn->strings[KSF_CONNALIAS],"KSF_CONNALIAS");
    }

    if(conn->options_set[KBF_PHASE2]) {
	conn->policy &= ~(POLICY_AUTHENTICATE|POLICY_ENCRYPT);
	conn->policy |= conn->options[KBF_PHASE2];
    }

    if(conn->options_set[KBF_IKEv2]) {
	switch(conn->options[KBF_IKEv2]) {
	case fo_never:
	    conn->policy &= ~POLICY_IKEV2_ALLOW;
	    break;

	case fo_permit:
	    /* this is the default for now */
	    conn->policy |= POLICY_IKEV2_ALLOW;
	    break;

	case fo_propose:
	    conn->policy |= POLICY_IKEV2_ALLOW|POLICY_IKEV2_PROPOSE;
	    break;

	case fo_insist:
	    conn->policy |= POLICY_IKEV1_DISABLE;
	    conn->policy |= POLICY_IKEV2_ALLOW|POLICY_IKEV2_PROPOSE;
	    break;
	}
    }

    if(conn->options_set[KBF_SAREFTRACK]) {
	switch(conn->options[KBF_SAREFTRACK]) {
	case sat_yes:
	    /* this is the default */
	    conn->policy |= POLICY_SAREF_TRACK;
	    break;

	case sat_conntrack:
	    conn->policy |= POLICY_SAREF_TRACK|POLICY_SAREF_TRACK_CONNTRACK;
	    break;

	case sat_no:
	    conn->policy &= ~POLICY_SAREF_TRACK;
	    conn->policy &= ~POLICY_SAREF_TRACK_CONNTRACK;
	    break;
	}
    }

    err += validate_end(conn, &conn->left,  TRUE,  resolvip, perr);
    err += validate_end(conn, &conn->right, FALSE, resolvip, perr);
    /*
     * TODO:
     * verify both ends are using the same inet family, if one end
     * is "%any" or "%defaultroute", then perhaps adjust it.
     * ensource this for left,leftnexthop,right,rightnexthop
     * Ideally, phase out connaddrfamily= which now wrongly assumes
     * left,leftnextop,leftsubnet are the same inet family
     * Currently, these tests are implicitely done, and wrongly
     * in case of 6in4 and 4in6 tunnels
     */


    if(conn->options_set[KBF_AUTO]) {
	conn->desired_state = conn->options[KBF_AUTO];
    }

    return err;
}
예제 #18
0
/**
 * Take keywords from ipsec.conf syntax and load into a conn struct
 *
 *
 * @param conn a connection definition
 * @param sl a section_list
 * @param assigned_value is set to either k_set, or k_default.
 *        k_default is used when we are loading a conn that should be
 *        considered to be a "default" value, and that replacing this
 *        value is considered acceptable.
 * @return bool 0 if successfull
 */
bool translate_conn (struct starter_conn *conn
		     , struct section_list *sl
		     , enum keyword_set   assigned_value
		     , err_t *error
                     , bool alsoflip)
{
    unsigned int err, field;
    ksf    *the_strings;
    knf    *the_options;
    str_set *set_strings;
    int_set *set_options;
    volatile int i;              /* just to keep it around for debugging */
    struct kw_list *kw = sl->kw;

    err = 0;
    i = 0;

    for ( ; kw; kw=kw->next)
    {
        char keyname[128];

	i++;
	the_strings = &conn->strings;
	set_strings = &conn->strings_set;
	the_options = &conn->options;
	set_options = &conn->options_set;

        /* initialize with base value */
        strcpy(keyname, kw->keyword.keydef->keyname);

        if((kw->keyword.keydef->validity & kv_conn) == 0)
	{
	    /* this isn't valid in a conn! */
	    *error = (const char *)tmp_err;

	    snprintf(tmp_err, sizeof(tmp_err),
		     "keyword '%s' is not valid in a conn (%s) (#%d)\n",
		     keyname, sl->name, i);
	    starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
	    continue;
	}

        if(kw->keyword.keydef->validity & kv_obsolete) {
	    starter_log(LOG_LEVEL_DEBUG,"Warning: obsolete keyword %s ignored\n",kw->keyword.keydef->keyname);
        }

        if(kw->keyword.keydef->validity & kv_leftright)
	{
            struct starter_end *left, *right;
            left  = &conn->left;
            right = &conn->right;
            if(alsoflip) {
                left = &conn->right;
                right= &conn->left;
            }

	    if(kw->keyword.keyleft)
	    {
                snprintf(keyname, sizeof(keyname), "left%s", kw->keyword.keydef->keyname);
		the_strings = &left->strings;
		the_options = &left->options;
		set_strings = &left->strings_set;
		set_options = &left->options_set;
	    } else {
                snprintf(keyname, sizeof(keyname), "right%s", kw->keyword.keydef->keyname);
		the_strings = &right->strings;
		the_options = &right->options;
		set_strings = &right->strings_set;
 		set_options = &right->options_set;
	    }
	}

	field = kw->keyword.keydef->field;

#ifdef PARSER_TYPE_DEBUG
	starter_log(LOG_LEVEL_DEBUG, "#analyzing %s[%d] kwtype=%d\n",
		    keyname, field,
		    kw->keyword.keydef->type);
#endif

	assert(kw->keyword.keydef != NULL);
	switch(kw->keyword.keydef->type)
	{
	case kt_string:
	case kt_filename:
	case kt_dirname:
	case kt_bitstring:
	case kt_ipaddr:
	case kt_subnet:
	case kt_idtype:
	    /* all treated as strings for now */
	    assert(kw->keyword.keydef->field < KEY_STRINGS_MAX);
	    if((*set_strings)[field] == k_set)
	    {
		*error = tmp_err;

                /* keyname[0] test looks for left=/right= */
		snprintf(tmp_err, sizeof(tmp_err)
			 , "duplicate key '%s' in conn %s while processing def %s (ignored)"
			 , keyname
			 , conn->name
			 , sl->name);

		starter_log(LOG_LEVEL_INFO, "%s", tmp_err);
		if(kw->keyword.string == NULL
		   || (*the_strings)[field] == NULL
		   || strcmp(kw->keyword.string, (*the_strings)[field])!=0)
		{
		    err++;
		    break;
		}
	    }
            pfreeany((*the_strings)[field]);

	    if(kw->keyword.string == NULL) {
		*error = tmp_err;

		snprintf(tmp_err, sizeof(tmp_err)
			 , "Invalid %s value"
			 , keyname);
		    err++;
		    break;
            }

            (*the_strings)[field] = clone_str(kw->keyword.string,"kt_idtype kw->keyword.string");
	    (*set_strings)[field] = assigned_value;
	    break;

	case kt_appendstring:
	case kt_appendlist:
	    /* implicitely, this field can have multiple values */
	    assert(kw->keyword.keydef->field < KEY_STRINGS_MAX);
	    if(!(*the_strings)[field])
	    {
                (*the_strings)[field] = clone_str(kw->keyword.string, "kt_appendlist kw->keyword.string");
	    } else {
                char *s = (*the_strings)[field];
                size_t old_len = strlen(s);	/* excludes '\0' */
                size_t new_len = strlen(kw->keyword.string);
                char *n;

                n = alloc_bytes(old_len + 1 + new_len + 1, "kt_appendlist");
                memcpy(n, s, old_len);
                n[old_len] = ' ';
                memcpy(n + old_len + 1, kw->keyword.string, new_len + 1);	/* includes '\0' */
                (*the_strings)[field] = n;
                pfree(s);
	    }
	    (*set_strings)[field] = TRUE;
	    break;

	case kt_rsakey:
	case kt_loose_enum:
	case kt_loose_enumarg:
	    assert(field < KEY_STRINGS_MAX);
	    assert(field < KEY_NUMERIC_MAX);

	    if((*set_options)[field] == k_set)
	    {
		*error = tmp_err;
		snprintf(tmp_err, sizeof(tmp_err)
			 , "duplicate key '%s' in conn %s while processing def %s"
			 , keyname
			 , conn->name
			 , sl->name);

		starter_log(LOG_LEVEL_INFO, "%s", tmp_err);

		/* only fatal if we try to change values */
		if((*the_options)[field] != kw->number
		   || !((*the_options)[field] == LOOSE_ENUM_OTHER
			&& kw->number == LOOSE_ENUM_OTHER
			&& kw->keyword.string != NULL
			&& (*the_strings)[field] != NULL
			&& strcmp(kw->keyword.string, (*the_strings)[field])==0))
		{
		    err++;
		    break;
		}
	    }

	    (*the_options)[field] = kw->number;
	    if(kw->number == LOOSE_ENUM_OTHER)
	    {
		assert(kw->keyword.string != NULL);
                pfreeany((*the_strings)[field]);
                (*the_strings)[field] = clone_str(kw->keyword.string, "kt_loose_enum kw->keyword.string");
                (*set_strings)[field] = TRUE;
	    } else if(kw->keyword.keydef->type == kt_loose_enumarg && kw->argument != NULL) {
                pfreeany((*the_strings)[field]);
                (*the_strings)[field] = clone_str(kw->argument, "kt_loose_enum kw->keyword.argument");
                (*set_strings)[field] = TRUE;
            }

	    (*set_options)[field] = assigned_value;
	    break;

	case kt_list:
	case kt_bool:
	case kt_invertbool:
	case kt_enum:
	case kt_number:
	case kt_time:
	case kt_percent:
	    /* all treated as a number for now */
	    assert(field < KEY_NUMERIC_MAX);

	    if((*set_options)[field] == k_set)
	    {
		starter_log(LOG_LEVEL_INFO
                            , "duplicate key '%s' in conn %s while processing def %s"
                            , keyname, conn->name, sl->name);
		if((*the_options)[field] != kw->number)
		{
		    err++;
		    break;
		}
	    }

#if 0
	    starter_log(LOG_LEVEL_DEBUG, "#setting %s[%d]=%u\n",
			keyname, field, kw->number);
#endif
	    (*the_options)[field] = kw->number;
	    (*set_options)[field] = assigned_value;
	    break;

	case kt_comment:
	    break;
	}
    }
    return err;
}
예제 #19
0
/**
 * 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
}
예제 #20
0
struct starter_config *confread_load(const char *file
				     , err_t *perr
				     , bool resolvip
				     , char *ctlbase
				     , bool setuponly)
{
	struct starter_config *cfg = NULL;
	struct config_parsed *cfgp;
	struct section_list *sconn;
	unsigned int err = 0, connerr;

	/**
	 * Load file
	 */
	cfgp = parser_load_conf(file, perr);
	if (!cfgp) return NULL;

	cfg = (struct starter_config *)alloc_bytes(sizeof(struct starter_config),"starter_config cfg");

	zero(cfg);

	/**
	 * Set default values
	 */
	ipsecconf_default_values(cfg);

	if(ctlbase) {
	    pfree(cfg->ctlbase);
	    cfg->ctlbase = clone_str(ctlbase, "control socket");
	}
        starter_whack_init_cfg(cfg); /* set default sender to send to socket */

	/**
	 * Load setup
	 */
	err += load_setup(cfg, cfgp);

	if(err) {
		parser_free_conf(cfgp);
		confread_free(cfg);
		return NULL;
	}

	if(!setuponly) {
	   /**
	    * Find %default and %oedefault conn
	    *
	    */
	   for(sconn = cfgp->sections.tqh_first; (!err) && sconn != NULL; sconn = sconn->link.tqe_next)
	   {
		if (strcmp(sconn->name,"%default")==0) {
			starter_log(LOG_LEVEL_DEBUG, "Loading default conn");
			err += load_conn (cfg, &cfg->conn_default,
					  cfgp, sconn, FALSE,
					  /*default conn*/TRUE,
					  resolvip, perr);
		}

		if (strcmp(sconn->name,"%oedefault")==0) {
			starter_log(LOG_LEVEL_DEBUG, "Loading oedefault conn");
			err += load_conn (cfg, &cfg->conn_oedefault,
					  cfgp, sconn, FALSE,
					  /*default conn*/TRUE,
					  resolvip, perr);
			if(err == 0) {
			    cfg->got_oedefault=TRUE;
			}
		}
	   }

	   /**
	    * Load other conns
	    */
	   for(sconn = cfgp->sections.tqh_first; sconn != NULL; sconn = sconn->link.tqe_next)
	   {
		if (strcmp(sconn->name,"%default")==0) continue;
		if (strcmp(sconn->name,"%oedefault")==0) continue;

		connerr = init_load_conn(cfg, cfgp, sconn, TRUE, FALSE,
					 resolvip, perr);

		if(connerr == -1) {
		    parser_free_conf(cfgp);
		    confread_free(cfg);
		    return NULL;
		}
		err += connerr;
	   }

	   /* if we have OE on, then create any missing OE conns! */
	   if(cfg->setup.options[KBF_OPPOENCRYPT]) {
	       starter_log(LOG_LEVEL_DEBUG, "Enabling OE conns\n");
	       add_any_oeconns(cfg, cfgp);
	   }
	}

	parser_free_conf(cfgp);

	return cfg;
}
예제 #21
0
struct starter_config *confread_load(const char *file,
				     err_t *perr,
				     bool resolvip,
				     const char *ctlbase,
				     bool setuponly)
{
	bool err = FALSE;

	/**
	 * Load file
	 */
	struct config_parsed *cfgp = parser_load_conf(file, perr);

	if (cfgp == NULL)
		return NULL;

	struct starter_config *cfg = alloc_thing(struct starter_config, "starter_config cfg");

	/**
	 * Set default values
	 */
	ipsecconf_default_values(cfg);

	if (ctlbase != NULL) {
		pfree(cfg->ctlbase);
		cfg->ctlbase = clone_str(ctlbase, "control socket");
	}

	/**
	 * Load setup
	 */
	err |= load_setup(cfg, cfgp);

	if (err) {
		parser_free_conf(cfgp);
		confread_free(cfg);
		return NULL;
	}

#ifdef DNSSEC
	struct ub_ctx *dnsctx = unbound_init();

	if (dnsctx == NULL)
		return NULL;
#endif

	if (!setuponly) {
		/**
		 * Find %default
		 *
		 */
		struct section_list *sconn;

		for (sconn = cfgp->sections.tqh_first; (!err) && sconn != NULL;
		     sconn = sconn->link.tqe_next) {
			if (streq(sconn->name, "%default")) {
				starter_log(LOG_LEVEL_DEBUG,
					    "Loading default conn");
				err |= load_conn(
#ifdef DNSSEC
						dnsctx,
#endif
						 &cfg->conn_default,
						 cfgp, sconn, FALSE,
						/*default conn*/ TRUE,
						 resolvip, perr);
			}
		}

		/**
		 * Load other conns
		 */
		for (sconn = cfgp->sections.tqh_first; sconn != NULL;
		     sconn = sconn->link.tqe_next) {
			if (streq(sconn->name, "%default"))
				continue;
			err |= init_load_conn(
#ifdef DNSSEC
						 dnsctx,
#endif
						 cfg, cfgp, sconn,
						 FALSE,
						 resolvip, perr);
		}
	}

	parser_free_conf(cfgp);
#ifdef DNSSEC
	ub_ctx_delete(dnsctx);
#endif
	return cfg;
}
예제 #22
0
static bool load_conn(
#ifdef DNSSEC
		     struct ub_ctx *dnsctx,
#endif
		     struct starter_conn *conn,
		     const struct config_parsed *cfgp,
		     struct section_list *sl,
		     bool alsoprocessing,
		     bool defaultconn,
		     bool resolvip,
		     err_t *perr)
{

	bool err;

	/* turn all of the keyword/value pairs into options/strings in left/right */
	err = translate_conn(conn, sl,
			defaultconn ? k_default : k_set,
			perr);

	move_comment_list(&conn->comments, &sl->comments);

	if (err)
		return err;

	if (conn->strings[KSCF_ALSO] != NULL &&
	    !alsoprocessing) {
		starter_log(LOG_LEVEL_INFO,
			    "also= is not valid in section '%s'",
			    sl->name);
		/* ??? should we not set *perr? */
		return TRUE;	/* error */
	}

	/* now, process the also's */
	if (conn->alsos != NULL)
		FREE_LIST(conn->alsos);
	conn->alsos = new_list(conn->strings[KSCF_ALSO]);

	if (alsoprocessing && conn->alsos != NULL) {
		struct section_list *sl1;
		/* note: for the duration of this loop body
		 * conn->alsos is migrated to local variable alsos.
		 */
		char **alsos = conn->alsos;
		int alsosize;
		int alsoplace;

		conn->alsos = NULL;

		/* reset all of the "beenhere" flags */
		for (sl1 = cfgp->sections.tqh_first; sl1 != NULL;
		     sl1 = sl1->link.tqe_next)
			sl1->beenhere = FALSE;
		sl->beenhere = TRUE;

		/* count them */
		for (alsosize = 0; alsos[alsosize] != NULL; alsosize++)
			;

		alsoplace = 0;
		while (alsoplace < alsosize && alsos[alsoplace] != NULL &&
		       alsoplace < ALSO_LIMIT) {
			/*
			 * for each also= listed, go find this section's keyword list, and
			 * load it as well. This may extend the also= list (and the end),
			 * which we handle by zeroing the also list, and adding to it after
			 * checking for duplicates.
			 */
			for (sl1 = cfgp->sections.tqh_first;
			     sl1 != NULL &&
			     !streq(alsos[alsoplace], sl1->name);
			     sl1 = sl1->link.tqe_next)
				;

			starter_log(LOG_LEVEL_DEBUG,
				    "\twhile loading conn '%s' also including '%s'",
				    conn->name, alsos[alsoplace]);

			/*
			 * if we found something that matches by name,
			 * and we haven't been there, then process it.
			 */
			if (sl1 != NULL && !sl1->beenhere) {
				conn->strings_set[KSCF_ALSO] = FALSE;
				pfreeany(conn->strings[KSCF_ALSO]);
				conn->strings[KSCF_ALSO] = NULL;
				sl1->beenhere = TRUE;

				/* translate things, but do not replace earlier settings! */
				err |= translate_conn(conn, sl1, k_set, perr);

				if (conn->strings[KSCF_ALSO] != NULL) {
					/* now, check out the KSCF_ALSO, and extend list if we need to */
					char **newalsos = new_list(
						conn->strings[KSCF_ALSO]);

					if (newalsos != NULL) {
						char **ra;
						int newalsoplace;

						/* count them */
						for (newalsoplace = 0;
						     newalsos[newalsoplace] !=
						     NULL;
						     newalsoplace++)
							;

						/* extend conn->alss */
						ra = alloc_bytes((alsosize +
							newalsoplace + 1) *
							sizeof(char *),
							"conn->alsos");
						memcpy(ra, alsos, alsosize * sizeof(char *));
						pfree(alsos);
						alsos = ra;
						for (newalsoplace = 0;
						     newalsos[newalsoplace] !=
						     NULL;
						     newalsoplace++) {
							assert(conn != NULL);
							assert(conn->name !=
								NULL);
							starter_log(
								LOG_LEVEL_DEBUG,
								"\twhile processing section '%s' added also=%s",
								sl1->name,
								newalsos[newalsoplace]);

							alsos[alsosize++] =
								clone_str(newalsos[newalsoplace],
									"alsos");
						}
						alsos[alsosize] = NULL;
					}

					FREE_LIST(newalsos);
				}
			}
			alsoplace++;
		}

		/* migrate alsos back to conn->alsos */
		conn->alsos = alsos;

		if (alsoplace >= ALSO_LIMIT) {
			starter_log(LOG_LEVEL_INFO,
				    "while loading conn '%s', too many also= used at section %s. Limit is %d",
				    conn->name,
				    alsos[alsoplace],
				    ALSO_LIMIT);
			/* ??? should we not set *perr? */
			return TRUE;	/* error */
		}
	}


	if (conn->options_set[KBF_TYPE]) {
		switch ((enum keyword_satype)conn->options[KBF_TYPE]) {
		case KS_TUNNEL:
			if (conn->options_set[KBF_AUTHBY] &&
				conn->options[KBF_AUTHBY] == POLICY_AUTH_NEVER) {
					*perr = "connection type=tunnel must not specify authby=never";
					return TRUE;
			}
			conn->policy |= POLICY_TUNNEL;
			conn->policy &= ~POLICY_SHUNT_MASK;
			break;

		case KS_TRANSPORT:
			if (conn->options_set[KBF_AUTHBY] &&
				conn->options[KBF_AUTHBY] == POLICY_AUTH_NEVER) {
					*perr = "connection type=transport must not specify authby=never";
					return TRUE;
			}
			conn->policy &= ~POLICY_TUNNEL;
			conn->policy &= ~POLICY_SHUNT_MASK;
			break;

		case KS_PASSTHROUGH:
			if (!conn->options_set[KBF_AUTHBY] ||
				conn->options[KBF_AUTHBY] != POLICY_AUTH_NEVER) {
					*perr = "connection type=passthrough must specify authby=never";
			}
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_PASS;
			break;

		case KS_DROP:
			if (!conn->options_set[KBF_AUTHBY] ||
				conn->options[KBF_AUTHBY] != POLICY_AUTH_NEVER) {
					*perr = "connection type=drop must specify authby=never";
			}
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_DROP;
			break;

		case KS_REJECT:
			if (!conn->options_set[KBF_AUTHBY] ||
				conn->options[KBF_AUTHBY] != POLICY_AUTH_NEVER) {
					*perr = "connection type=drop must specify authby=never";
			}
			conn->policy &=
				~(POLICY_ENCRYPT | POLICY_AUTHENTICATE |
				  POLICY_TUNNEL | POLICY_RSASIG);
			conn->policy &= ~POLICY_SHUNT_MASK;
			conn->policy |= POLICY_SHUNT_REJECT;
			break;
		}
	}

	if (conn->options_set[KBF_FAILURESHUNT]) {
		conn->policy &= ~POLICY_FAIL_MASK;
		switch (conn->options[KBF_FAILURESHUNT]) {
		case KFS_FAIL_NONE:
			conn->policy |= POLICY_FAIL_NONE;
			break;
		case KFS_FAIL_PASS:
			conn->policy |= POLICY_FAIL_PASS;
			break;
		case KFS_FAIL_DROP:
			conn->policy |= POLICY_FAIL_DROP;
			break;
		case KFS_FAIL_REJECT:
			conn->policy |= POLICY_FAIL_REJECT;
			break;
		}
	}

	if (conn->options_set[KBF_NEGOTIATIONSHUNT]) {
		switch (conn->options[KBF_NEGOTIATIONSHUNT]) {
		case KNS_FAIL_PASS:
			conn->policy |= POLICY_NEGO_PASS;
			break;
		case KNS_FAIL_DROP:
			conn->policy &= ~POLICY_NEGO_PASS;
			break;
		}
	}

	KW_POLICY_FLAG(KBF_COMPRESS, POLICY_COMPRESS);
	KW_POLICY_FLAG(KBF_PFS, POLICY_PFS);

	/* reset authby= flags */
	if (conn->options_set[KBF_AUTHBY]) {

		conn->policy &= ~POLICY_ID_AUTH_MASK;
		conn->policy |= conn->options[KBF_AUTHBY];

	}

	KW_POLICY_NEGATIVE_FLAG(KBF_IKEPAD, POLICY_NO_IKEPAD);

	KW_POLICY_NEGATIVE_FLAG(KBF_REKEY, POLICY_DONT_REKEY);

	KW_POLICY_FLAG(KBF_AGGRMODE, POLICY_AGGRESSIVE);

	KW_POLICY_FLAG(KBF_MODECONFIGPULL, POLICY_MODECFG_PULL);

	KW_POLICY_FLAG(KBF_OVERLAPIP, POLICY_OVERLAPIP);

	KW_POLICY_FLAG(KBF_IKEv2_ALLOW_NARROWING,
		       POLICY_IKEV2_ALLOW_NARROWING);

	KW_POLICY_FLAG(KBF_IKEv2_PAM_AUTHORIZE,
		       POLICY_IKEV2_PAM_AUTHORIZE);

#	define str_to_conn(member, kscf) { \
		if (conn->strings_set[kscf]) \
			conn->member = clone_str(conn->strings[kscf], #kscf); \
	}

	str_to_conn(esp, KSCF_ESP);

#ifdef HAVE_LABELED_IPSEC
	str_to_conn(policy_label, KSCF_POLICY_LABEL);
	if (conn->policy_label != NULL)
		starter_log(LOG_LEVEL_DEBUG, "connection's policy label: %s",
				conn->policy_label);
#endif

	str_to_conn(ike, KSCF_IKE);
	str_to_conn(modecfg_dns1, KSCF_MODECFGDNS1);
	str_to_conn(modecfg_dns2, KSCF_MODECFGDNS2);
	str_to_conn(modecfg_domain, KSCF_MODECFGDOMAIN);
	str_to_conn(modecfg_banner, KSCF_MODECFGBANNER);

	/* mark-in= and mark-out= override mark= */
	str_to_conn(conn_mark_in, KSCF_CONN_MARK_BOTH);
	str_to_conn(conn_mark_out, KSCF_CONN_MARK_BOTH);
	str_to_conn(conn_mark_in, KSCF_CONN_MARK_IN);
	str_to_conn(conn_mark_out, KSCF_CONN_MARK_OUT);
	str_to_conn(vti_iface, KSCF_VTI_IFACE);

	str_to_conn(connalias, KSCF_CONNALIAS);

#	undef str_to_conn

	if (conn->options_set[KBF_PHASE2]) {
		conn->policy &= ~(POLICY_AUTHENTICATE | POLICY_ENCRYPT);
		conn->policy |= conn->options[KBF_PHASE2];
	}

	if (conn->options_set[KBF_IKEv2]) {
		lset_t pv2 = LEMPTY;

		switch (conn->options[KBF_IKEv2]) {
		case fo_never:
			pv2 = POLICY_IKEV1_ALLOW;
			break;

		case fo_permit:
			/* this is the default for now */
			pv2 = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW;
			break;

		case fo_propose:
			pv2 = POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
			break;

		case fo_insist:
			pv2 =                      POLICY_IKEV2_ALLOW | POLICY_IKEV2_PROPOSE;
			break;
		}
		conn->policy = (conn->policy & ~POLICY_IKEV2_MASK) | pv2;
	}

	if (conn->options_set[KBF_ESN]) {
		conn->policy &= ~(POLICY_ESN_NO | POLICY_ESN_YES);

		switch (conn->options[KBF_ESN]) {
		case esn_yes:
			conn->policy |= POLICY_ESN_YES;
			break;

		case esn_no:
			/* this is the default for now */
			conn->policy |= POLICY_ESN_NO;
			break;

		case esn_either:
			conn->policy |= POLICY_ESN_NO | POLICY_ESN_YES;
			break;
		}
	}

	if (conn->options_set[KBF_IKE_FRAG]) {
		conn->policy &= ~(POLICY_IKE_FRAG_ALLOW | POLICY_IKE_FRAG_FORCE);

		switch (conn->options[KBF_IKE_FRAG]) {
		case ynf_no:
			break;

		case ynf_yes:
			/* this is the default */
			conn->policy |= POLICY_IKE_FRAG_ALLOW;
			break;

		case ynf_force:
			conn->policy |= POLICY_IKE_FRAG_ALLOW |
					POLICY_IKE_FRAG_FORCE;
			break;
		}
	}

	if (conn->options_set[KBF_SAREFTRACK]) {
		conn->policy &= ~(POLICY_SAREF_TRACK | POLICY_SAREF_TRACK_CONNTRACK);

		switch (conn->options[KBF_SAREFTRACK]) {
		case sat_yes:
			/* this is the default */
			conn->policy |= POLICY_SAREF_TRACK;
			break;

		case sat_conntrack:
			conn->policy |= POLICY_SAREF_TRACK |
					POLICY_SAREF_TRACK_CONNTRACK;
			break;

		case sat_no:
			break;
		}
	}

	/*
	 * some options are set as part of our default, but
	 * some make no sense for shunts, so remove those again
	 */
	if (NEVER_NEGOTIATE(conn->policy)) {
		/* remove IPsec related options */
		conn->policy &= ~(POLICY_PFS | POLICY_COMPRESS | POLICY_ESN_NO |
			POLICY_ESN_YES | POLICY_SAREF_TRACK |
			POLICY_SAREF_TRACK_CONNTRACK);
		/* remove IKE related options */
		conn->policy &= ~(POLICY_IKEV1_ALLOW | POLICY_IKEV2_ALLOW |
			POLICY_IKEV2_PROPOSE | POLICY_IKE_FRAG_ALLOW |
			POLICY_IKE_FRAG_FORCE);
	}


	err |= validate_end(
#ifdef DNSSEC
		dnsctx,
#endif
		conn, &conn->left, "left", resolvip, perr);
	err |= validate_end(
#ifdef DNSSEC
		dnsctx,
#endif
		conn, &conn->right, "right", resolvip, perr);
	/*
	 * TODO:
	 * verify both ends are using the same inet family, if one end
	 * is "%any" or "%defaultroute", then perhaps adjust it.
	 * ensource this for left,leftnexthop,right,rightnexthop
	 * Ideally, phase out connaddrfamily= which now wrongly assumes
	 * left,leftnextop,leftsubnet are the same inet family
	 * Currently, these tests are implicitely done, and wrongly
	 * in case of 6in4 and 4in6 tunnels
	 */

	if (conn->options_set[KBF_AUTO])
		conn->desired_state = conn->options[KBF_AUTO];

	return err;
}
예제 #23
0
static int _iface_up (int sock,  struct st_ipsec_if *iface, char *phys,
                      unsigned int mtu, int nat_t)
{
    struct ifreq req;
    struct ipsectunnelconf *shc=(struct ipsectunnelconf *)&req.ifr_data;
    short phys_flags;
    int ret = 0;

    strncpy(req.ifr_name, phys, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) {
        return ret;
    }
    phys_flags = req.ifr_flags;

    strncpy(req.ifr_name, iface->name, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) {
        return ret;
    }

    if ((!(req.ifr_flags & IFF_UP)) || (!iface->up)) {
        starter_log(LOG_LEVEL_INFO, "attaching interface %s to %s", iface->name,
                    phys);
        ret = 1;
    }

    if ((*iface->phys) && (strcmp(iface->phys, phys)!=0)) {
        /* tncfg --detach if phys has changed */
        strncpy(req.ifr_name, iface->name, IFNAMSIZ);
        ioctl(sock, IPSEC_DEL_DEV, &req);
        ret = 1;
    }

    /* tncfg --attach */
    strncpy(req.ifr_name, iface->name, IFNAMSIZ);
    strncpy(shc->cf_name, phys, sizeof(shc->cf_name));
    ioctl(sock, IPSEC_SET_DEV, &req);

    /* set ipsec addr = phys addr */
    strncpy(req.ifr_name, phys, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFADDR, &req)==0) {
        strncpy(req.ifr_name, iface->name, IFNAMSIZ);
        ioctl(sock, SIOCSIFADDR, &req);
    }

    /* set ipsec mask = phys mask */
    strncpy(req.ifr_name, phys, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFNETMASK, &req)==0) {
        strncpy(req.ifr_name, iface->name, IFNAMSIZ);
        ioctl(sock, SIOCSIFNETMASK, &req);
    }

    /* set other flags & addr */
    strncpy(req.ifr_name, iface->name, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &req)==0) {
        if (phys_flags & IFF_POINTOPOINT) {
            req.ifr_flags |= IFF_POINTOPOINT;
            req.ifr_flags &= ~IFF_BROADCAST;
            ioctl(sock, SIOCSIFFLAGS, &req);
            strncpy(req.ifr_name, phys, IFNAMSIZ);
            if (ioctl(sock, SIOCGIFDSTADDR, &req)==0) {
                strncpy(req.ifr_name, iface->name, IFNAMSIZ);
                ioctl(sock, SIOCSIFDSTADDR, &req);
            }
        }
        else if (phys_flags & IFF_BROADCAST) {
            req.ifr_flags &= ~IFF_POINTOPOINT;
            req.ifr_flags |= IFF_BROADCAST;
            ioctl(sock, SIOCSIFFLAGS, &req);
            strncpy(req.ifr_name, phys, IFNAMSIZ);
            if (ioctl(sock, SIOCGIFBRDADDR, &req)==0) {
                strncpy(req.ifr_name, iface->name, IFNAMSIZ);
                ioctl(sock, SIOCSIFBRDADDR, &req);
            }
        }
        else {
            req.ifr_flags &= ~IFF_POINTOPOINT;
            req.ifr_flags &= ~IFF_BROADCAST;
            ioctl(sock, SIOCSIFFLAGS, &req);
        }
    }

    /*
     * guess MTU = phys interface MTU - ESP Overhead
     *
     * ESP overhead : 10+16+7+2+12=57 -> 60 by security
     * NAT-T overhead : 20
     */
    if (mtu==0) {
        strncpy(req.ifr_name, phys, IFNAMSIZ);
        ioctl(sock, SIOCGIFMTU, &req);
        mtu = req.ifr_mtu - 60;
        if (nat_t) mtu -= 20;
    }
    /* set MTU */
    if (mtu) {
        strncpy(req.ifr_name, iface->name, IFNAMSIZ);
        req.ifr_mtu = mtu;
        ioctl(sock, SIOCSIFMTU, &req);
    }

    /* ipsec interface UP */
    strncpy(req.ifr_name, iface->name, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &req)==0) {
        req.ifr_flags |= IFF_UP;
        ioctl(sock, SIOCSIFFLAGS, &req);
    }

    iface->up = 1;
    strncpy(iface->phys, phys, IFNAMSIZ);
    return ret;
}
예제 #24
0
int starter_start_pluto (struct starter_config *cfg, int debug)
{
	int i;
	struct stat stb;
	pid_t pid;
	char *arg[] = { PLUTO_CMD, "--nofork", NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
	int argc = 2;

	if (debug) {
		arg[argc++] = "--stderrlog";
	}
	if (cfg->setup.options[KBF_UNIQUEIDS]) {
		arg[argc++] = "--uniqueids";
	}
	if(cfg->setup.options[KBF_PLUTODEBUG] & DBG_ALL)
	{
	    arg[argc++] = "--debug-all";
	} else {
	    ADD_DEBUG(DBG_RAW,   "raw");
	    ADD_DEBUG(DBG_CRYPT, "crypt");
	    ADD_DEBUG(DBG_PARSING,"parsing");
	    ADD_DEBUG(DBG_EMITTING,"emitting");
	    ADD_DEBUG(DBG_CONTROL, "control");
	    ADD_DEBUG(DBG_CONTROLMORE, "controlmore");
	    ADD_DEBUG(DBG_KLIPS, "klips");
	    ADD_DEBUG(DBG_DNS,   "dns");
	    ADD_DEBUG(DBG_OPPO,  "oppo");
	    ADD_DEBUG(DBG_PRIVATE, "private");
	    ADD_DEBUG(IMPAIR_DELAY_ADNS_KEY_ANSWER, "impair-delay-adns-key-answer");
	    ADD_DEBUG(IMPAIR_DELAY_ADNS_TXT_ANSWER,"impair-delay-adns-txt-answer");
	    ADD_DEBUG(IMPAIR_BUST_MI2, "impair-bust-mi2");
	    ADD_DEBUG(IMPAIR_BUST_MR2, "impair-bust-mr2");
	}

	if (cfg->setup.strictcrlpolicy) {
		arg[argc++] = "--strictcrlpolicy";
	}
	if (cfg->setup.nocrsend) {
		arg[argc++] = "--nocrsend";
	}
#ifdef NAT_TRAVERSAL
	{
		static char ka[15];
		if (cfg->setup.nat_traversal) {
			arg[argc++] = "--nat_traversal";
		}
		if (cfg->setup.keep_alive) {
			arg[argc++] = "--keep_alive";
			sprintf(ka, "%u", cfg->setup.keep_alive);
			arg[argc++] = ka;
		}
	}
#endif
#ifdef VIRTUAL_IP
	if (cfg->setup.virtual_private) {
		arg[argc++] = "--virtual_private";
		arg[argc++] = cfg->setup.virtual_private;
	}
#endif

	if (_pluto_pid) {
		starter_log(LOG_LEVEL_ERR,
			"starter_start_pluto(): pluto already started...");
		return -1;
	}
	else {
		unlink(CTL_FILE);
		_stop_requested = 0;

		if (cfg->setup.strings[KSF_PREPLUTO]) system(cfg->setup.strings[KSF_PREPLUTO]);

		pid = fork();
		switch (pid) {
			case -1:
				starter_log(LOG_LEVEL_ERR, "can't fork(): %s", strerror(errno));
				return -1;
				break;
			case 0:
				/**
				 * Child
				 */
				setsid();
				sigsetmask(0);
				execv(arg[0], arg);
				starter_log(LOG_LEVEL_ERR, "can't execv(%s,...): %s", arg[0],
					strerror(errno));
				exit(1);
				break;
			default:
				/**
				 * Father
				 */
				_pluto_pid = pid;
				for (i=0; (i<50) && (_pluto_pid); i++) {
					/**
					 * Wait for pluto
					 */
					usleep(20000);
					if (stat(CTL_FILE, &stb)==0) {
						starter_log(LOG_LEVEL_INFO, "pluto (%d) started",
							_pluto_pid);
						if (cfg->setup.strings[KSF_POSTPLUTO])
						{
						    system(cfg->setup.strings[KSF_POSTPLUTO]);
						}
						return 0;
					}
				}
				if (_pluto_pid) {
					/**
					 * If pluto is started but with no ctl file, stop it
					 */
					starter_log(LOG_LEVEL_ERR,
						"pluto too long to start... - kill kill");
					for (i=0; (i<20) && ((pid=_pluto_pid)!=0); i++) {
						if (i<10) kill(pid, SIGTERM);
						else kill(pid, SIGKILL);
						usleep(20000);
					}
				}
				else {
					starter_log(LOG_LEVEL_ERR, "pluto refused to be started");
				}
				return -1;
				break;
		}
	}
	return -1;
}