kernel.c

来自「ipsec vpn」· C语言 代码 · 共 2,050 行 · 第 1/5 页

C
2,050
字号
    if (st->st_ipcomp.present)    {        ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi;        unsigned compalg;        switch (st->st_ipcomp.attrs.transid)        {            case IPCOMP_DEFLATE:                compalg = SADB_X_CALG_DEFLATE;                break;            default:                loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented"                    , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid));                goto fail;        }        set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP);        said_next->src = &src.addr;        said_next->dst = &dst.addr;        said_next->src_client = &src_client;        said_next->dst_client = &dst_client;        said_next->spi = ipcomp_spi;        said_next->satype = SADB_X_SATYPE_COMP;        said_next->encalg = compalg;        said_next->encapsulation = encapsulation;        said_next->reqid = c->spd.reqid + 2;        said_next->text_said = text_said;        if (!kernel_ops->add_sa(said_next, replace)) {	    DBG_log("add_sa ipcomp failed");            goto fail;	}        said_next++;        encapsulation = ENCAPSULATION_MODE_TRANSPORT;    }    /* set up ESP SA, if any */    if (st->st_esp.present)    {        ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;        u_char *esp_dst_keymat = inbound? st->st_esp.our_keymat : st->st_esp.peer_keymat;        const struct esp_info *ei;        u_int16_t key_len;        static const struct esp_info esp_info[] = {            { FALSE, ESP_NULL, AUTH_ALGORITHM_HMAC_MD5,                0, HMAC_MD5_KEY_LEN,                SADB_EALG_NULL, SADB_AALG_MD5HMAC },            { FALSE, ESP_NULL, AUTH_ALGORITHM_HMAC_SHA1,                0, HMAC_SHA1_KEY_LEN,                SADB_EALG_NULL, SADB_AALG_SHA1HMAC },            { FALSE, ESP_DES, AUTH_ALGORITHM_NONE,                DES_CBC_BLOCK_SIZE, 0,                SADB_EALG_DESCBC, SADB_AALG_NONE },            { FALSE, ESP_DES, AUTH_ALGORITHM_HMAC_MD5,                DES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN,                SADB_EALG_DESCBC, SADB_AALG_MD5HMAC },            { FALSE, ESP_DES, AUTH_ALGORITHM_HMAC_SHA1,                DES_CBC_BLOCK_SIZE,                HMAC_SHA1_KEY_LEN, SADB_EALG_DESCBC, SADB_AALG_SHA1HMAC },            { FALSE, ESP_3DES, AUTH_ALGORITHM_NONE,                DES_CBC_BLOCK_SIZE * 3, 0,                SADB_EALG_3DESCBC, SADB_AALG_NONE },            { FALSE, ESP_3DES, AUTH_ALGORITHM_HMAC_MD5,                DES_CBC_BLOCK_SIZE * 3, HMAC_MD5_KEY_LEN,                SADB_EALG_3DESCBC, SADB_AALG_MD5HMAC },            { FALSE, ESP_3DES, AUTH_ALGORITHM_HMAC_SHA1,                DES_CBC_BLOCK_SIZE * 3, HMAC_SHA1_KEY_LEN,                SADB_EALG_3DESCBC, SADB_AALG_SHA1HMAC },            { FALSE, ESP_AES, AUTH_ALGORITHM_NONE,                AES_CBC_BLOCK_SIZE, 0,                SADB_X_EALG_AESCBC, SADB_AALG_NONE },            { FALSE, ESP_AES, AUTH_ALGORITHM_HMAC_MD5,                AES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN,                SADB_X_EALG_AESCBC, SADB_AALG_MD5HMAC },            { FALSE, ESP_AES, AUTH_ALGORITHM_HMAC_SHA1,                AES_CBC_BLOCK_SIZE, HMAC_SHA1_KEY_LEN,                SADB_X_EALG_AESCBC, SADB_AALG_SHA1HMAC },        };	//static const int esp_max = elemsof(esp_info);	//int esp_count;#ifdef NAT_TRAVERSAL        u_int8_t natt_type = 0;        u_int16_t natt_sport = 0, natt_dport = 0;        ip_address natt_oa;        if (st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) {	    if(st->hidden_variables.st_nat_traversal & NAT_T_WITH_PORT_FLOATING) {		natt_type = ESPINUDP_WITH_NON_ESP;	    } else {		natt_type = ESPINUDP_WITH_NON_IKE;	    }	       	    if(inbound) {		natt_sport = st->st_remoteport;		natt_dport = st->st_localport;	    } else {		natt_sport = st->st_localport;		natt_dport = st->st_remoteport;	    }		            natt_oa = st->hidden_variables.st_nat_oa;        }#endif	DBG(DBG_CRYPT	    , DBG_log("looking for alg with transid: %d keylen: %d auth: %d\n"		      , st->st_esp.attrs.transid		      , st->st_esp.attrs.key_len		      , st->st_esp.attrs.auth));		            for (ei = esp_info; ; ei++)        {	    	    /* if it is the last key entry, then ask algo */            if (ei == &esp_info[elemsof(esp_info)])            {                /* Check for additional kernel alg */#ifdef KERNEL_ALG                if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid,					    st->st_esp.attrs.key_len,					    st->st_esp.attrs.auth))!=NULL) {                        break;                }#endif                /* note: enum_show may use a static buffer, so two                 * calls in one printf would be a mistake.                 * enum_name does the same job, without a static buffer,                 * assuming the name will be found.                 */                loglog(RC_LOG_SERIOUS, "ESP transform %s(%d) / auth %s not implemented yet"                    , enum_name(&esp_transformid_names, st->st_esp.attrs.transid)		       , st->st_esp.attrs.key_len                    , enum_name(&auth_alg_names, st->st_esp.attrs.auth));                goto fail;            }	    DBG(DBG_CRYPT		, DBG_log("checking transid: %d keylen: %d auth: %d\n"			  , ei->transid, ei->enckeylen, ei->auth));		                if (st->st_esp.attrs.transid == ei->transid		&& (st->st_esp.attrs.key_len ==0 || st->st_esp.attrs.key_len == ei->enckeylen*8)		&& st->st_esp.attrs.auth == ei->auth)                break;        }	if (st->st_esp.attrs.transid != ei->transid	    && st->st_esp.attrs.key_len != ei->enckeylen*8  	    && st->st_esp.attrs.auth != ei->auth) {	    loglog(RC_LOG_SERIOUS, "failed to find key info for %s/%s"		   , enum_name(&esp_transformid_names, st->st_esp.attrs.transid)		   , enum_name(&auth_alg_names, st->st_esp.attrs.auth));	    goto fail;	}        key_len = st->st_esp.attrs.key_len/8;        if (key_len) {                /* XXX: must change to check valid _range_ key_len */                if (key_len > ei->enckeylen) {                        loglog(RC_LOG_SERIOUS, "ESP transform %s passed key_len=%d > %d",                        enum_name(&esp_transformid_names, st->st_esp.attrs.transid),                        (int)key_len, (int)ei->enckeylen);                        goto fail;                }        } else {                key_len = ei->enckeylen;        }        /* Grrrrr.... f*cking 7 bits jurassic algos  */        /* 168 bits in kernel, need 192 bits for keymat_len */        if (ei->transid == ESP_3DES && key_len == 21)                 key_len = 24;        /* 56 bits in kernel, need 64 bits for keymat_len */        if (ei->transid == ESP_DES && key_len == 7)                 key_len = 8;        /* divide up keying material */        /* passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen); */	if(st->st_esp.keymat_len != key_len + ei->authkeylen)	    DBG_log("keymat_len=%d key_len=%d authkeylen=%d",		    st->st_esp.keymat_len, (int)key_len, (int)ei->authkeylen);        passert(st->st_esp.keymat_len == (key_len + ei->authkeylen));        set_text_said(text_said, &dst.addr, esp_spi, SA_ESP);        said_next->src = &src.addr;        said_next->dst = &dst.addr;        said_next->src_client = &src_client;        said_next->dst_client = &dst_client;        said_next->spi = esp_spi;        said_next->satype = SADB_SATYPE_ESP;        said_next->replay_window = kernel_ops->replay_window;        said_next->authalg = ei->authalg;        said_next->authkeylen = ei->authkeylen;        /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */        said_next->authkey = esp_dst_keymat + key_len;        said_next->encalg = ei->encryptalg;        /* said_next->enckeylen = ei->enckeylen; */        said_next->enckeylen = key_len;        said_next->enckey = esp_dst_keymat;        said_next->encapsulation = encapsulation;        said_next->reqid = c->spd.reqid + 1;#ifdef NAT_TRAVERSAL        said_next->natt_sport = natt_sport;        said_next->natt_dport = natt_dport;        said_next->transid = st->st_esp.attrs.transid;        said_next->natt_type = natt_type;        said_next->natt_oa = &natt_oa;#endif          said_next->text_said = text_said;        if (!kernel_ops->add_sa(said_next, replace))            goto fail;        said_next++;        encapsulation = ENCAPSULATION_MODE_TRANSPORT;    }    /* set up AH SA, if any */    if (st->st_ah.present)    {        ipsec_spi_t ah_spi = inbound? st->st_ah.our_spi : st->st_ah.attrs.spi;        u_char *ah_dst_keymat = inbound? st->st_ah.our_keymat : st->st_ah.peer_keymat;        unsigned char authalg;        switch (st->st_ah.attrs.auth)        {        case AUTH_ALGORITHM_HMAC_MD5:            authalg = SADB_AALG_MD5HMAC;            break;        case AUTH_ALGORITHM_HMAC_SHA1:            authalg = SADB_AALG_SHA1HMAC;            break;        case AUTH_ALGORITHM_KPDK:        case AUTH_ALGORITHM_DES_MAC:        default:            loglog(RC_LOG_SERIOUS, "%s not implemented yet"                , enum_show(&auth_alg_names, st->st_ah.attrs.auth));            goto fail;        }        set_text_said(text_said, &dst.addr, ah_spi, SA_AH);        said_next->src = &src.addr;        said_next->dst = &dst.addr;        said_next->src_client = &src_client;        said_next->dst_client = &dst_client;        said_next->spi = ah_spi;        said_next->satype = SADB_SATYPE_AH;        said_next->replay_window = kernel_ops->replay_window;        said_next->authalg = authalg;        said_next->authkeylen = st->st_ah.keymat_len;        said_next->authkey = ah_dst_keymat;        said_next->encapsulation = encapsulation;        said_next->reqid = c->spd.reqid;        said_next->text_said = text_said;        if (!kernel_ops->add_sa(said_next, replace))            goto fail;        said_next++;        encapsulation = ENCAPSULATION_MODE_TRANSPORT;    }    if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL    || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL    || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL)    {        encapsulation = ENCAPSULATION_MODE_TUNNEL;    }    if (kernel_ops->inbound_eroute ? c->spd.eroute_owner == SOS_NOBODY        : encapsulation == ENCAPSULATION_MODE_TUNNEL)    {        /* If inbound, and policy does not specifie DISABLEARRIVALCHECK,         * tell KLIPS to enforce the IP addresses appropriate for this tunnel.         * Note reversed ends.         * Not much to be done on failure.         */        if (inbound && (c->policy & POLICY_DISABLEARRIVALCHECK) == 0)        {            struct pfkey_proto_info proto_info[4];            int i = 0;                        if (st->st_ipcomp.present)            {                proto_info[i].proto = IPPROTO_COMP;                proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation;                proto_info[i].reqid = c->spd.reqid + 2;                i++;            }                        if (st->st_esp.present)            {                proto_info[i].proto = IPPROTO_ESP;                proto_info[i].encapsulation = st->st_esp.attrs.encapsulation;                proto_info[i].reqid = c->spd.reqid + 1;                i++;            }                        if (st->st_ah.present)            {                proto_info[i].proto = IPPROTO_AH;                proto_info[i].encapsulation = st->st_ah.attrs.encapsulation;                proto_info[i].reqid = c->spd.reqid;                i++;            }                        proto_info[i].proto = 0;                        if (kernel_ops->inbound_eroute                && encapsulation == ENCAPSULATION_MODE_TUNNEL)            {                proto_info[0].encapsulation = ENCAPSULATION_MODE_TUNNEL;                for (i = 1; proto_info[i].proto; i++)                {                    proto_info[i].encapsulation = ENCAPSULATION_MODE_TRANSPORT;                }            }                        /* MCR - should be passed a spd_eroute structure here */            (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client                              , &c->spd.this.host_addr, &c->spd.this.client                              , inner_spi, proto                              , c->spd.this.protocol                              , satype                              , proto_info, 0                              , ERO_ADD_INBOUND, "add inbound");        }    }    /* If there are multiple SPIs, group them. */        if (kernel_ops->grp_sa && said_next > &said[1])    {        struct kernel_sa *s;                /* group SAs, two at a time, inner to outer (backwards in said[])         * The grouping is by pairs.  So if said[] contains ah esp ipip,         * the grouping would be ipip:esp, esp:ah.         */        for (s = said; s < said_next-1; s++)        {            char                text_said0[SATOT_BUF],                text_said1[SATOT_BUF];            /* group s[1] and s[0], in that order */                        set_text_said(text_said0, s[0].dst, s[0].spi, s[0].proto);            set_text_said(text_said1, s[1].dst, s[1].spi, s[1].proto);                        DBG(DBG_KLIPS, DBG_log("grouping %s and %s", text_said1, text_said0));                        s[0].text_said = text_said0;            s[1].text_said = text_said1;                        if (!kernel_ops->grp_sa(s + 1, s))                goto fail;        }        /* could update said, but it will not be used */    }#ifdef DEBUG    /* if the impaired is set, pretend this fails */    if(st->st_connection->extra_debugging & IMPAIR_SA_CREATION) {	DBG_log("Impair SA creation is set, pretending to fail");	goto fail;    }#endif    return TRUE;fail:    {        /* undo the done SPIs */        while (said_next-- != said) {	    if(said_next->proto) {		(void) del_spi(said_next->spi, said_next->proto			       , &src.addr, said_next->dst);	    }	}        return FALSE;    }}/* teardown_ipsec_sa is a canibalized version of setup_ipsec_sa */static boolteardown_half_ipsec_sa(struct state *st, bool inbound){    /* We n

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?