📄 state.c
字号:
#if 1void for_each_state(void *(f)(struct state *, void *data), void *data){ struct state *st, *ocs = cur_state; int i; for (i=0; i<STATE_TABLE_SIZE; i++) { for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { set_cur_state(st); f(st, data); } } cur_state = ocs;}#endif/* * Find a state object. */struct state *find_state(const u_char *icookie, const u_char *rcookie, const ip_address *peer, msgid_t /*network order*/ msgid){ struct state *st = *state_hash(icookie, rcookie, peer); while (st != (struct state *) NULL) { if (sameaddr(peer, &st->st_connection->spd.that.host_addr) && memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0 && memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0) { DBG(DBG_CONTROL, DBG_log("peer and cookies match on #%ld, provided msgid %08x vs %08x" , st->st_serialno , ntohl(msgid), ntohl(st->st_msgid))); if(msgid == st->st_msgid) break;#if 0 if(msgid == st->st_msgid2) { u_char tmpiv[MAX_DIGEST_LEN]; /* oh, damn, life is bad, they reused the old one */ openswan_log("find_state: old message id %08x reused, Coping." , msgid); /* swap msgid/msgid2 and the IVs */ /* msgid already == st->st_msgid2 */ st->st_msgid2 = st->st_msgid; st->st_msgid = msgid; save_iv(st, tmpiv); set_iv(st, st->st_old_iv); memcpy(st->st_old_iv, tmpiv, MAX_DIGEST_LEN); break; }#endif } st = st->st_hashchain_next; } DBG(DBG_CONTROL, if (st == NULL) DBG_log("state object not found"); else DBG_log("state object #%lu found, in %s" , st->st_serialno , enum_show(&state_names, st->st_state))); return st;}/* * Find a state object. */struct state *find_info_state(const u_char *icookie , const u_char *rcookie , const ip_address *peer , msgid_t /*network order*/ msgid){ struct state *st = *state_hash(icookie, rcookie, peer); int i; bool found = FALSE; struct state *best = NULL; for(;st != (struct state *) NULL; st = st->st_hashchain_next) { if (sameaddr(peer, &st->st_connection->spd.that.host_addr) && memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0 && memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0) { DBG(DBG_CONTROL, DBG_log("peer and cookies match on #%ld, provided msgid %08x vs %08x" , st->st_serialno , ntohl(msgid), ntohl(st->st_msgid))); if(msgid == st->st_msgid) best = st; /* perfect match is best */ else { found = FALSE; for(i=0; i < MAX_INFO_EXG && !found; i++) { if(msgid == st->st_infoid[i]) found=TRUE; /* need to do something with the IVs, I think */ /* XXX but not yet */ } /* only pick this one if there is no better one */ if(found) { if(best == NULL) best = st; } } } } DBG(DBG_CONTROL, if (best == NULL) DBG_log("state object not found"); else DBG_log("state object #%lu found, in %s" , best->st_serialno , enum_show(&state_names, best->st_state))); return best;}/* Find the state that sent a packet * ??? this could be expensive -- it should be rate-limited to avoid DoS */struct state *find_sender(size_t packet_len, u_char *packet){ int i; struct state *st; if (packet_len >= sizeof(struct isakmp_hdr)) for (i = 0; i < STATE_TABLE_SIZE; i++) for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) if (st->st_tpacket.ptr != NULL && st->st_tpacket.len == packet_len && memcmp(st->st_tpacket.ptr, packet, packet_len) == 0) return st; return NULL;}struct state *find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid, ipsec_spi_t spi, bool *bogus){ struct state *st; int i; *bogus = FALSE; for (i = 0; i < STATE_TABLE_SIZE; i++) { for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { if (IS_IPSEC_SA_ESTABLISHED(st->st_state) && p1st->st_connection->host_pair == st->st_connection->host_pair && same_peer_ids(p1st->st_connection, st->st_connection, NULL)) { struct ipsec_proto_info *pr = protoid == PROTO_IPSEC_AH ? &st->st_ah : &st->st_esp; if (pr->present) { if (pr->attrs.spi == spi) return st; if (pr->our_spi == spi) *bogus = TRUE; } } } } return NULL;}/* Find newest Phase 1 negotiation state object for suitable for connection c */struct state *find_phase1_state(const struct connection *c, lset_t ok_states){ struct state *st, *best = NULL; int i; for (i = 0; i < STATE_TABLE_SIZE; i++) for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) if (LHAS(ok_states, st->st_state) && c->host_pair == st->st_connection->host_pair && same_peer_ids(c, st->st_connection, NULL) && (best == NULL || best->st_serialno < st->st_serialno)) best = st; return best;}voidstate_eroute_usage(ip_subnet *ours, ip_subnet *his, unsigned long count, time_t nw){ struct state *st; int i; for (i = 0; i < STATE_TABLE_SIZE; i++) { for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { struct connection *c = st->st_connection; /* XXX spd-enum */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) && c->spd.eroute_owner == st->st_serialno && c->spd.routing == RT_ROUTED_TUNNEL && samesubnet(&c->spd.this.client, ours) && samesubnet(&c->spd.that.client, his)) { if (st->st_outbound_count != count) { st->st_outbound_count = count; st->st_outbound_time = nw; } return; } } } DBG(DBG_CONTROL, { char ourst[SUBNETTOT_BUF]; char hist[SUBNETTOT_BUF]; subnettot(ours, 0, ourst, sizeof(ourst)); subnettot(his, 0, hist, sizeof(hist)); DBG_log("unknown tunnel eroute %s -> %s found in scan" , ourst, hist); });}void fmt_state(struct state *st, time_t n, char *state_buf, size_t state_buf_len, char *state_buf2, size_t state_buf2_len){ /* what the heck is interesting about a state? */ const struct connection *c = st->st_connection; long delta; char inst[CONN_INST_BUF]; char dpdbuf[128]; const char *np1 = c->newest_isakmp_sa == st->st_serialno ? "; newest ISAKMP" : ""; const char *np2 = c->newest_ipsec_sa == st->st_serialno ? "; newest IPSEC" : ""; /* XXX spd-enum */ const char *eo = c->spd.eroute_owner == st->st_serialno ? "; eroute owner" : ""; fmt_conn_instance(c, inst); if(st->st_event) { delta = st->st_event->ev_time >= n ? (long)(st->st_event->ev_time - n) : -(long)(n - st->st_event->ev_time); } else { delta = -1; } if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { dpdbuf[0]='\0'; } else { if(st->hidden_variables.st_dpd) { time_t n = time(NULL); snprintf(dpdbuf, sizeof(dpdbuf), "; lastdpd=%lds(seq in:%u out:%u)" , st->st_last_dpd !=0 ? n - st->st_last_dpd : -1 , st->st_dpd_seqno , st->st_dpd_expectseqno); } else { snprintf(dpdbuf, sizeof(dpdbuf), "; nodpd"); } } snprintf(state_buf, state_buf_len , "#%lu: \"%s\"%s %s (%s); %s in %lds%s%s%s%s" , st->st_serialno , c->name, inst , enum_name(&state_names, st->st_state) , state_story[st->st_state - STATE_MAIN_R0] , st->st_event ? enum_name(&timer_event_names, st->st_event->ev_type) : "none" , delta , np1, np2, eo, dpdbuf); /* print out SPIs if SAs are established */ if (state_buf2_len != 0) state_buf2[0] = '\0'; /* default to empty */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { char lastused[40]; /* should be plenty long enough */ char buf[SATOT_BUF*6 + 1]; char *p = buf;# define add_said(adst, aspi, aproto) { \ ip_said s; \ \ initsaid(adst, aspi, aproto, &s); \ if (p < &buf[sizeof(buf)-1]) \ { \ *p++ = ' '; \ p += satot(&s, 0, p, &buf[sizeof(buf)] - p) - 1; \ } \ } /* XXX - mcr last used is really an attribute of the connection */ lastused[0] = '\0'; if (c->spd.eroute_owner == st->st_serialno && st->st_outbound_count != 0) { snprintf(lastused, sizeof(lastused) , " used %lus ago;" , (unsigned long) (now() - st->st_outbound_time)); } *p = '\0'; if (st->st_ah.present) { add_said(&c->spd.that.host_addr, st->st_ah.attrs.spi, SA_AH); add_said(&c->spd.this.host_addr, st->st_ah.our_spi, SA_AH); } if (st->st_esp.present) { add_said(&c->spd.that.host_addr, st->st_esp.attrs.spi, SA_ESP); add_said(&c->spd.this.host_addr, st->st_esp.our_spi, SA_ESP); } if (st->st_ipcomp.present) { add_said(&c->spd.that.host_addr, st->st_ipcomp.attrs.spi, SA_COMP); add_said(&c->spd.this.host_addr, st->st_ipcomp.our_spi, SA_COMP); }#ifdef KLIPS 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) { add_said(&c->spd.that.host_addr, st->st_tunnel_out_spi, SA_IPIP); add_said(&c->spd.this.host_addr, st->st_tunnel_in_spi, SA_IPIP); }#endif snprintf(state_buf2, state_buf2_len , "#%lu: \"%s\"%s%s%s" , st->st_serialno , c->name, inst , lastused , buf);# undef add_said }}/* * sorting logic is: * * name * type * instance# * isakmp_sa (XXX probably wrong) * */static intstate_compare(const void *a, const void *b){ const struct state *sap = *(const struct state *const *)a; struct connection *ca = sap->st_connection; const struct state *sbp = *(const struct state *const *)b; struct connection *cb = sbp->st_connection; /* DBG_log("comparing %s to %s", ca->name, cb->name); */ return connection_compare(ca, cb);}voidshow_states_status(void){ time_t n = now(); int i; char state_buf[LOG_WIDTH]; char state_buf2[LOG_WIDTH]; int count; struct state **array; /* make count of states */ count = 0; for (i = 0; i < STATE_TABLE_SIZE; i++) { struct state *st; for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { count++; } } /* build the array */ array = alloc_bytes(sizeof(struct state *)*count, "state array"); count = 0; for (i = 0; i < STATE_TABLE_SIZE; i++) { struct state *st; for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { array[count++]=st; } } /* sort it! */ qsort(array, count, sizeof(struct state *), state_compare); /* now print sorted results */ for (i = 0; i < count; i++) { struct state *st; st = array[i]; fmt_state(st, n, state_buf, sizeof(state_buf) , state_buf2, sizeof(state_buf2)); whack_log(RC_COMMENT, state_buf); if (state_buf2[0] != '\0') whack_log(RC_COMMENT, state_buf2); /* show any associated pending Phase 2s */ if (IS_PHASE1(st->st_state)) show_pending_phase2(st->st_connection->host_pair, st); } /* free the array */ pfree(array);}/* Given that we've used up a range of unused CPI's, * search for a new range of currently unused ones. * Note: this is very expensive when not trivial! * If we can't find one easily, choose 0 (a bad SPI, * no matter what order) indicating failure. */voidfind_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi){ int tries = 0; cpi_t base = *latest_cpi; cpi_t closest; int i;startover: closest = ~0; /* not close at all */ for (i = 0; i < STATE_TABLE_SIZE; i++) { struct state *st; for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { if (st->st_ipcomp.present) { cpi_t c = ntohl(st->st_ipcomp.our_spi) - base; if (c < closest) { if (c == 0) { /* oops: next spot is occupied; start over */ if (++tries == 20) { /* FAILURE */ *latest_cpi = *first_busy_cpi = 0; return; } base++; if (base > IPCOMP_LAST_NEGOTIATED) base = IPCOMP_FIRST_NEGOTIATED; goto startover; /* really a tail call */ } closest = c; } } } } *latest_cpi = base; /* base is first in next free range */ *first_busy_cpi = closest + base; /* and this is the roof */}/* Muck with high-order 16 bits of this SPI in order to make * the corresponding SAID unique. * Its low-order 16 bits hold a well-known IPCOMP CPI. * Oh, and remember that SPIs are stored in network order. * Kludge!!! So I name it with the non-English word "uniquify". * If we can't find one easily, return 0 (a bad SPI, * no matter what order) indicating failure. */ipsec_spi_tuniquify_his_cpi(ipsec_spi_t cpi, struct state *st){ int tries = 0; int i;startover: /* network order makes first two bytes our target */ get_rnd_bytes((u_char *)&cpi, 2); /* Make sure that the result is unique. * Hard work. If there is no unique value, we'll loop forever! */ for (i = 0; i < STATE_TABLE_SIZE; i++) { struct state *s; for (s = statetable[i]; s != NULL; s = s->st_hashchain_next) { if (s->st_ipcomp.present && sameaddr(&s->st_connection->spd.that.host_addr , &st->st_connection->spd.that.host_addr) && cpi == s->st_ipcomp.attrs.spi) { if (++tries == 20) return 0; /* FAILURE */ goto startover; } } } return cpi;}/* * Immediately schedule a replace event for all states for a peer. */void replace_states_by_peer(ip_address *peer){ struct state *st = NULL; int i; /* struct event *ev; currently unused */ for (i = 0; st == NULL && i < STATE_TABLE_SIZE; i++) for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) /* Only replace if it already has a replace event. */ if (sameaddr(&st->st_connection->spd.that.host_addr, peer) && (IS_ISAKMP_SA_ESTABLISHED(st->st_state) || IS_IPSEC_SA_ESTABLISHED(st->st_state)) && st->st_event->ev_type == EVENT_SA_REPLACE) { delete_event(st); delete_dpd_event(st); event_schedule(EVENT_SA_REPLACE, 0, st); }}void copy_quirks(struct isakmp_quirks *dq , struct isakmp_quirks *sq){ dq->xauth_ack_msgid |= sq->xauth_ack_msgid; dq->modecfg_pull_mode |= sq->modecfg_pull_mode; dq->nat_traversal_vid |= sq->nat_traversal_vid;}/* * Local Variables: * c-basic-offset:4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -