Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Commit

Permalink
QoS for UDP encapsulat. IKE phase 1 rekeying. IKE keepalive RFC 2948.…
Browse files Browse the repository at this point in the history
… [Jeff Layton <[email protected]>
  • Loading branch information
breiter committed Jul 3, 2015
1 parent 2956a0f commit 6de7b71
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 28 deletions.
58 changes: 55 additions & 3 deletions tunip.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,9 +458,15 @@ static void encap_esp_send_peer(struct sa_block *s, unsigned char *buf, unsigned
static void encap_udp_send_peer(struct sa_block *s, unsigned char *buf, unsigned int bufsize)
{
ssize_t sent;
struct ip *tip;
uint8_t tos;

buf += MAX_HEADER;

/* get the TOS value of the original frame */
tip = (struct ip *)buf;
tos = (bufsize < sizeof(struct ip)) ? 0 : tip->ip_tos;

s->ipsec.tx.buf = buf;
s->ipsec.tx.buflen = bufsize;

Expand All @@ -480,6 +486,15 @@ static void encap_udp_send_peer(struct sa_block *s, unsigned char *buf, unsigned
memset(s->ipsec.tx.buf, 0, 8);
}

/* set outer TOS header to the one of the original frame */
/* but only if it differs from the already set TOS */
if (tos != s->ipsec.current_udp_tos) {
if (setsockopt(s->esp_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) {
logmsg(LOG_ERR, "udp setsockopt: %m");
}
s->ipsec.current_udp_tos = tos;
}

sent = send(s->esp_fd, s->ipsec.tx.buf, s->ipsec.tx.buflen, 0);
if (sent == -1) {
logmsg(LOG_ERR, "udp sendto: %m");
Expand Down Expand Up @@ -885,10 +900,32 @@ static void vpnc_main_loop(struct sa_block *s)
uint8_t *keepalive;
size_t keepalive_size;

/* the below code had keepalive_v2 for NATT_ACTIVE_RFC [FIXME]
* however, ASA 9.4(1) produced
* [IKEv1]: IKE Receiver: Runt ISAKMP packet discarded on Port 4500 from ip:port
* according to RFC 3948, the keepalive should be 0xFF
*
* 2.3. NAT-Keepalive Packet Format
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source Port | Destination Port |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Length | Checksum |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0xFF |
* +-+-+-+-+-+-+-+-+
*
*/

if (s->ipsec.natt_active_mode == NATT_ACTIVE_DRAFT_OLD) {
keepalive = keepalive_v1;
keepalive_size = sizeof(keepalive_v1);
} else { /* active_mode is either RFC or CISCO_UDP */
} else if (s->ipsec.natt_active_mode == NATT_ACTIVE_RFC) {
keepalive = keepalive_v1;
keepalive_size = sizeof(keepalive_v1);
} else { /* active_mode is CISCO_UDP */
keepalive = keepalive_v2;
keepalive_size = sizeof(keepalive_v2);
}
Expand Down Expand Up @@ -964,6 +1001,7 @@ static void vpnc_main_loop(struct sa_block *s)
keepalive_ike(s);
}
/* send nat keepalive packet */
DEBUG(3,printf("keepalive %d\n", (int)keepalive_size));
if (send(s->esp_fd, keepalive, keepalive_size, 0) == -1) {
logmsg(LOG_ERR, "keepalive sendto: %m");
}
Expand All @@ -983,12 +1021,26 @@ static void vpnc_main_loop(struct sa_block *s)
}
}
}
DEBUG(2,printf("lifetime status: %ld of %u seconds used, %u|%u of %u kbytes used\n",
DEBUG(2,printf("lifetime status: %ld of %u seconds used, %u|%u of %u kbytes used, ike: %ld of %u seconds used\n",
time(NULL) - s->ipsec.life.start,
s->ipsec.life.seconds,
s->ipsec.life.rx/1024,
s->ipsec.life.tx/1024,
s->ipsec.life.kbytes));
s->ipsec.life.kbytes,
time(NULL) - s->ike.life.start,
s->ike.life.seconds));

if (timed_mode) {
time_t now = time(NULL);

/* start rekey at 80% of lifetime */
if ((now - s->ike.life.start) + ((s->ike.life.seconds*20)/100) > s->ike.life.seconds) {
DEBUG(3,printf("starting phase1 rekey at %d s\n", s->ike.life.seconds));
rekey_phase1(s);
}
}


} while ((presult == 0 || (presult == -1 && errno == EINTR)) && !do_kill);
if (presult == -1) {
logmsg(LOG_ERR, "select: %m");
Expand Down
1 change: 1 addition & 0 deletions tunip.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct sa_block {
struct ike_sa rx, tx;
struct encap_method *em;
uint16_t ip_id;
uint8_t current_udp_tos;
} ipsec;
};

Expand Down
105 changes: 80 additions & 25 deletions vpnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,7 @@ void keepalive_ike(struct sa_block *s)

gcry_create_nonce((uint8_t *) & msgid, sizeof(msgid));
sendrecv_phase2(s, NULL, ISAKMP_EXCHANGE_INFORMATIONAL, msgid, 1, 0, 0, 0, 0);
DEBUG(3, printf("sent IKE keepalive\n"));
}

static void send_dpd(struct sa_block *s, int isack, uint32_t seqno)
Expand Down Expand Up @@ -816,6 +817,7 @@ void dpd_ike(struct sa_block *s)
s->ike.dpd_sent = now;
send_dpd(s, 0, s->ike.dpd_seqno);
}
DEBUG(3, printf("sent DPD packet\n"));
}

static void send_delete_ipsec(struct sa_block *s)
Expand Down Expand Up @@ -843,7 +845,7 @@ static void send_delete_ipsec(struct sa_block *s)
}
}

static void send_delete_isakmp(struct sa_block *s)
static void send_delete_isakmp_cookie(struct sa_block *s, uint8_t *i_cookie, uint8_t *r_cookie)
{
DEBUGTOP(2, printf("S7.11 send isakmp termination message\n"));
{
Expand All @@ -858,15 +860,21 @@ static void send_delete_isakmp(struct sa_block *s)
d_isakmp->u.d.num_spi = 1;
d_isakmp->u.d.spi = xallocc(1 * sizeof(uint8_t *));
d_isakmp->u.d.spi[0] = xallocc(2 * ISAKMP_COOKIE_LENGTH);
memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 0, s->ike.i_cookie,
memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 0, i_cookie,
ISAKMP_COOKIE_LENGTH);
memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 1, s->ike.r_cookie,
memcpy(d_isakmp->u.d.spi[0] + ISAKMP_COOKIE_LENGTH * 1, r_cookie,
ISAKMP_COOKIE_LENGTH);
sendrecv_phase2(s, d_isakmp, ISAKMP_EXCHANGE_INFORMATIONAL,
del_msgid, 1, NULL, 0, NULL, 0);
}
}

static void send_delete_isakmp(struct sa_block *s)
{
DEBUGTOP(2, printf("S7.11 send isakmp termination message\n"));
send_delete_isakmp_cookie(s, s->ike.i_cookie, s->ike.r_cookie);
}

static void phase2_fatal(struct sa_block *s, const char *msg, int id)
{
struct isakmp_payload *pl;
Expand Down Expand Up @@ -2000,6 +2008,7 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
default:
abort();
}
DEBUG(1, printf("NAT-T mode: %d\n", natt_draft));
if (natt_draft >= 2) {
s->ipsec.natt_active_mode = NATT_ACTIVE_RFC;
close(s->ike_fd);
Expand Down Expand Up @@ -2027,7 +2036,7 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
}
}

static void do_phase1_am_packet3(struct sa_block *s)
static void do_phase1_am_packet3(struct sa_block *s, int re_key)
{
DEBUGTOP(2, printf("S4.5 AM_packet3\n"));
/* Send final phase 1 packet. */
Expand All @@ -2044,16 +2053,18 @@ static void do_phase1_am_packet3(struct sa_block *s)
p2->isakmp_version = ISAKMP_VERSION;
p2->exchange_type = ISAKMP_EXCHANGE_AGGRESSIVE;
/* XXX CERT Add id(?), cert and sig here in case of cert auth */
p2->payload = new_isakmp_data_payload(ISAKMP_PAYLOAD_HASH,
p2->payload = pl = new_isakmp_data_payload(ISAKMP_PAYLOAD_HASH,
s->ike.returned_hash, s->ike.md_len);
p2->payload->next = pl = new_isakmp_payload(ISAKMP_PAYLOAD_N);
pl->u.n.doi = ISAKMP_DOI_IPSEC;
pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
pl->u.n.type = ISAKMP_N_IPSEC_INITIAL_CONTACT;
pl->u.n.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
pl->u.n.spi = xallocc(2 * ISAKMP_COOKIE_LENGTH);
memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 0, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);
memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 1, s->ike.r_cookie, ISAKMP_COOKIE_LENGTH);
if (!re_key) {
p2->payload->next = pl = new_isakmp_payload(ISAKMP_PAYLOAD_N);
pl->u.n.doi = ISAKMP_DOI_IPSEC;
pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
pl->u.n.type = ISAKMP_N_IPSEC_INITIAL_CONTACT;
pl->u.n.spi_length = 2 * ISAKMP_COOKIE_LENGTH;
pl->u.n.spi = xallocc(2 * ISAKMP_COOKIE_LENGTH);
memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 0, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);
memcpy(pl->u.n.spi + ISAKMP_COOKIE_LENGTH * 1, s->ike.r_cookie, ISAKMP_COOKIE_LENGTH);
}

/* send PSK-hash if hybrid authentication is negotiated */
if (s->ike.auth_algo == IKE_AUTH_HybridInitRSA ||
Expand Down Expand Up @@ -2119,17 +2130,17 @@ static void do_phase1_am_cleanup(struct sa_block *s)
s->ike.returned_hash = NULL;
}

static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_block *s)
static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_block *s, int re_key)
{
do_phase1_am_init(s);
do_phase1_am_packet1(s, key_id);
do_phase1_am_packet2(s, shared_key);
do_phase1_am_packet3(s);
do_phase1_am_packet3(s, re_key);
do_phase1_am_cleanup(s);
}

static int do_phase2_notice_check(struct sa_block *s, struct isakmp_packet **r_p,
const uint8_t * nonce, size_t nonce_size)
const uint8_t * nonce, size_t nonce_size, int life_only)
{
int reject = 0;
struct isakmp_packet *r;
Expand Down Expand Up @@ -2172,6 +2183,7 @@ static int do_phase2_notice_check(struct sa_block *s, struct isakmp_packet **r_p
lifetime_ipsec_process(s, r->payload->next->u.n.attributes);
else
DEBUG(2, printf("got unknown lifetime notice, ignoring..\n"));
if (life_only) return 0;
r_length = sendrecv(s, r_packet, sizeof(r_packet), NULL, 0, 0);
continue;
} else if (r->payload->next->u.n.type == ISAKMP_N_IPSEC_INITIAL_CONTACT) {
Expand Down Expand Up @@ -2220,7 +2232,7 @@ static int do_phase2_xauth(struct sa_block *s)
/* recv and check for notices */
if (r) free_isakmp_packet(r);
r = NULL;
reject = do_phase2_notice_check(s, &r, NULL, 0);
reject = do_phase2_notice_check(s, &r, NULL, 0, 0);
if (reject == -1) {
if (r) free_isakmp_packet(r);
return 1;
Expand Down Expand Up @@ -2407,7 +2419,7 @@ static int do_phase2_xauth(struct sa_block *s)
ISAKMP_EXCHANGE_MODECFG_TRANSACTION,
r->message_id, 0, 0, 0, 0, 0);

reject = do_phase2_notice_check(s, &r, NULL, 0);
reject = do_phase2_notice_check(s, &r, NULL, 0, 0);
if (reject == -1) {
free_isakmp_packet(r);
return 1;
Expand Down Expand Up @@ -2498,7 +2510,7 @@ static int do_phase2_config(struct sa_block *s)

DEBUGTOP(2, printf("S6.2 phase2_config receive modecfg\n"));
/* recv and check for notices */
reject = do_phase2_notice_check(s, &r, NULL, 0);
reject = do_phase2_notice_check(s, &r, NULL, 0, 0);
if (reject == -1) {
if (r) free_isakmp_packet(r);
return 1;
Expand Down Expand Up @@ -2646,7 +2658,7 @@ static void do_phase2_qm(struct sa_block *s)
msgid, 0, 0, 0, 0, 0);

DEBUGTOP(2, printf("S7.3 QM_packet2 validate type\n"));
reject = do_phase2_notice_check(s, &r, nonce_i, sizeof(nonce_i)); /* FIXME: LEAK */
reject = do_phase2_notice_check(s, &r, nonce_i, sizeof(nonce_i), 0); /* FIXME: LEAK */

/* Check the transaction type & message ID are OK. */
if (reject == 0 && r->message_id != msgid)
Expand Down Expand Up @@ -3088,14 +3100,22 @@ static int do_rekey(struct sa_block *s, struct isakmp_packet *r)

void process_late_ike(struct sa_block *s, uint8_t *r_packet, ssize_t r_length)
{
int reject;
int reject = 0;
struct isakmp_packet *r;
struct isakmp_payload *rp;

DEBUG(2,printf("got late ike packet: %zd bytes\n", r_length));
/* we should ignore resent packets here.
* unpack_verify_phase2 will fail to decode them probably */
reject = unpack_verify_phase2(s, r_packet, r_length, &r, NULL, 0);

if (r_length > ISAKMP_PAYLOAD_O && r_packet[ISAKMP_EXCHANGE_TYPE_O] == ISAKMP_EXCHANGE_AGGRESSIVE) {
DEBUG(2,printf("can't respond to phase1 aggressive... terminating\n"));
do_kill = -1;
return;
} else {
/* we should ignore resent pakets here.
* unpack_verify_phase2 will fail to decode them probably */
DEBUG(2,printf("processing as phase2\n"));
reject = unpack_verify_phase2(s, r_packet, r_length, &r, NULL, 0);
}

/* just ignore broken stuff for now */
if (reject != 0) {
Expand Down Expand Up @@ -3126,6 +3146,7 @@ void process_late_ike(struct sa_block *s, uint8_t *r_packet, ssize_t r_length)
}

if (r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL) {
DEBUG(3, printf("got ISAKMP_EXCHANGE_INFORMATIONAL\n"));
/* Search for notify payloads */
for (rp = r->payload->next; rp; rp = rp->next) {
if (rp->type != ISAKMP_PAYLOAD_N)
Expand Down Expand Up @@ -3159,6 +3180,14 @@ void process_late_ike(struct sa_block *s, uint8_t *r_packet, ssize_t r_length)
continue;
}
DEBUG(2, printf("got r-u-there ack\n"));
} else if (rp->u.n.type == ISAKMP_N_IPSEC_RESPONDER_LIFETIME) {
if (r->payload->next->u.n.protocol == ISAKMP_IPSEC_PROTO_ISAKMP)
lifetime_ike_process(s, r->payload->next->u.n.attributes);
else if (r->payload->next->u.n.protocol == ISAKMP_IPSEC_PROTO_IPSEC_ESP)
lifetime_ipsec_process(s, r->payload->next->u.n.attributes);
else
DEBUG(2, printf("got unknown lifetime notice, ignoring..\n"));

}
}
}
Expand Down Expand Up @@ -3227,6 +3256,9 @@ int main(int argc, char **argv)
s->ipsec.encap_mode = IPSEC_ENCAP_TUNNEL;
s->ike.timeout = 1000; /* 1 second */

/* initialize last set TOS value in case UDP encap used */
s->ipsec.current_udp_tos = 0;

do_config(argc, argv);

DEBUG(1, printf("\nvpnc version " VERSION "\n"));
Expand All @@ -3245,7 +3277,7 @@ int main(int argc, char **argv)
do_load_balance = 0;
do {
DEBUGTOP(2, printf("S4 do_phase1_am\n"));
do_phase1_am(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], s);
do_phase1_am(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], s, 0);
DEBUGTOP(2, printf("S5 do_phase2_xauth\n"));
/* FIXME: Create and use a generic function in supp.[hc] */
if (s->ike.auth_algo >= IKE_AUTH_HybridInitRSA)
Expand Down Expand Up @@ -3276,3 +3308,26 @@ int main(int argc, char **argv)

return 0;
}

void rekey_phase1(struct sa_block *s) {
struct isakmp_packet *r;
uint8_t i_cookie[ISAKMP_COOKIE_LENGTH], r_cookie[ISAKMP_COOKIE_LENGTH];

memcpy(i_cookie, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);
memcpy(r_cookie, s->ike.r_cookie, ISAKMP_COOKIE_LENGTH);

do_phase1_am(config[CONFIG_IPSEC_ID], config[CONFIG_IPSEC_SECRET], s, 1);

(void)do_phase2_xauth(s);

DEBUG(3, printf("notice_checks\n"));
r_length = sendrecv(s, r_packet, sizeof(r_packet), NULL, 0, 0);
do_phase2_notice_check(s, &r, NULL, 0, 1);
if (r) free_isakmp_packet(r);
DEBUG(3, printf("notice_checks done\n"));

/* delete the old SA and read the response */
DEBUG(3, printf("delete old cookie\n"));
send_delete_isakmp_cookie(s, i_cookie, r_cookie);
}

2 changes: 2 additions & 0 deletions vpnc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ void process_late_ike(struct sa_block *s, uint8_t *r_packet, ssize_t r_length);
void keepalive_ike(struct sa_block *s);
void dpd_ike(struct sa_block *s);
void print_vid(const unsigned char *vid, uint16_t len);
void rekey_phase1(struct sa_block *s);


#endif

0 comments on commit 6de7b71

Please sign in to comment.