kernel.c
来自「ipsec vpn」· C语言 代码 · 共 2,050 行 · 第 1/5 页
C
2,050 行
return 0; } ugh = ttoul(p+1, l-((p-s)+1), 10, &proto); if (ugh != 0) return ugh; if (proto > 65535) return "protocol number is too large, legal range is 0-65535"; *len = p-s; *transport_proto = proto; return 0;}/* scan /proc/net/ipsec_eroute every once in a while, looking for: * * - %hold shunts of which Pluto isn't aware. This situation could * be caused by lost ACQUIRE messages. When found, they will * added to orphan_holds. This in turn will lead to Opportunistic * initiation. * * - other kinds of shunts that haven't been used recently. These will be * deleted. They represent OE failures. * * - recording recent uses of tunnel eroutes so that rekeying decisions * can be made for OE connections. * * Here are some sample lines: * 10 10.3.2.1.0/24 -> 0.0.0.0/0 => %trap * 259 10.3.2.1.115/32 -> 10.19.75.161/32 => tun0x1002@10.19.75.145 * 71 10.44.73.97/32 -> 0.0.0.0/0 => %trap * 4119 10.44.73.97/32 -> 10.114.121.41/32 => %pass * Newer versions of KLIPS start each line with a 32-bit packet count. * If available, the count is used to detect whether a %pass shunt is in use. * * NOTE: execution time is quadratic in the number of eroutes since the * searching for each is sequential. If this becomes a problem, faster * searches could be implemented (hash or radix tree, for example). */voidscan_proc_shunts(void){ static const char procname[] = "/proc/net/ipsec_eroute"; FILE *f; time_t nw = now(); int lino; struct eroute_info *expired = NULL; event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); DBG(DBG_CONTROL, DBG_log("scanning for shunt eroutes") ) /* free any leftover entries: they will be refreshed if still current */ while (orphaned_holds != NULL) { struct eroute_info *p = orphaned_holds; orphaned_holds = p->next; pfree(orphaned_holds); } /* decode the /proc file. Don't do anything strenuous to it * (certainly no PF_KEY stuff) to minimize the chance that it * might change underfoot. */ f = fopen(procname, "r"); if (f == NULL) return; /* for each line... */ for (lino = 1; ; lino++) { unsigned char buf[1024]; /* should be big enough */ chunk_t field[10]; /* 10 is loose upper bound */ chunk_t *ff; /* fixed fields (excluding optional count) */ int fi; struct eroute_info eri; char *cp; err_t context = "" , ugh = NULL; ff = NULL; cp = fgets(buf, sizeof(buf), f); if (cp == NULL) break; /* break out each field * Note: if there are too many fields, just stop; * it will be diagnosed a little later. */ for (fi = 0; fi < (int)elemsof(field); fi++) { static const char sep[] = " \t\n"; /* field-separating whitespace */ size_t w; cp += strspn(cp, sep); /* find start of field */ w = strcspn(cp, sep); /* find width of field */ setchunk(field[fi], cp, w); cp += w; if (w == 0) break; } /* This odd do-hickey is to share error reporting code. * A break will get to that common code. The setting * of "ugh" and "context" parameterize it. */ do { /* Old entries have no packet count; new ones do. * check if things are as they should be. */ if (fi == 5) ff = &field[0]; /* old form, with no count */ else if (fi == 6) ff = &field[1]; /* new form, with count */ else { ugh = "has wrong number of fields"; break; } if (ff[1].len != 2 || strncmp(ff[1].ptr, "->", 2) != 0 || ff[3].len != 2 || strncmp(ff[3].ptr, "=>", 2) != 0) { ugh = "is missing -> or =>"; break; } /* actually digest fields of interest */ /* packet count */ eri.count = 0; if (ff != field) { context = "count field is malformed: "; ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count); if (ugh != NULL) break; } /* our client */ context = "source subnet field malformed: "; ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours); if (ugh != NULL) break; /* his client */ context = "destination subnet field malformed: "; ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his); if (ugh != NULL) break; /* SAID */ context = "SA ID field malformed: "; ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto); if (ugh != NULL) break; ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said); } while (FALSE); if (ugh != NULL) { openswan_log("INTERNAL ERROR: %s line %d %s%s" , procname, lino, context, ugh); continue; /* ignore rest of line */ } /* Now we have decoded eroute, let's consider it. * For shunt eroutes: * * %hold: if not known, add to orphaned_holds list for initiation * because ACQUIRE might have been lost. * * %pass, %drop, %reject: determine if idle; if so, blast it away. * Can occur bare (if DNS provided insufficient information) * or with a connection (failure context). * Could even be installed by ipsec manual. * * %trap: always welcome. * * For other eroutes: find state and record count change */ if (eri.said.proto == SA_INT) { /* shunt eroute */ switch (ntohl(eri.said.spi)) { case SPI_HOLD: if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL && shunt_owner(&eri.ours, &eri.his) == NULL) { int ourport = ntohs(portof(&eri.ours.addr)); int hisport = ntohs(portof(&eri.his.addr)); char ourst[SUBNETTOT_BUF]; char hist[SUBNETTOT_BUF]; char sat[SATOT_BUF]; subnettot(&eri.ours, 0, ourst, sizeof(ourst)); subnettot(&eri.his, 0, hist, sizeof(hist)); satot(&eri.said, 0, sat, sizeof(sat)); DBG(DBG_CONTROL, DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d" , ourst, ourport, hist, hisport, sat, eri.transport_proto) ) eri.next = orphaned_holds; orphaned_holds = clone_thing(eri, "orphaned %hold"); } break; case SPI_PASS: case SPI_DROP: case SPI_REJECT: /* nothing sensible to do if we don't have counts */ if (ff != field) { struct bare_shunt **bs_pp = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto); if (bs_pp != NULL) { struct bare_shunt *bs = *bs_pp; if (eri.count != bs->count) { bs->count = eri.count; bs->last_activity = nw; } else if (nw - bs->last_activity > SHUNT_PATIENCE) { eri.next = expired; expired = clone_thing(eri, "expired %pass"); } } } break; case SPI_TRAP: break; default: bad_case(ntohl(eri.said.spi)); } } else { /* regular (non-shunt) eroute */ state_eroute_usage(&eri.ours, &eri.his, eri.count, nw); } } /* for each line */ fclose(f); /* Now that we've finished processing the /proc file, * it is safe to delete the expired %pass shunts. */ while (expired != NULL) { struct eroute_info *p = expired; ip_address src, dst; networkof(&p->ours, &src); networkof(&p->his, &dst); (void) replace_bare_shunt(&src, &dst , BOTTOM_PRIO /* not used because we are deleting. This value is a filler */ , SPI_PASS /* not used because we are deleting. This value is a filler */ , FALSE, p->transport_proto, "delete expired bare shunts"); expired = p->next; pfree(p); }}static booldel_spi(ipsec_spi_t spi, int proto, const ip_address *src, const ip_address *dest){ char text_said[SATOT_BUF]; struct kernel_sa sa; set_text_said(text_said, dest, spi, proto); DBG(DBG_KLIPS, DBG_log("delete %s", text_said)); memset(&sa, 0, sizeof(sa)); sa.spi = spi; sa.proto = proto; sa.src = src; sa.dst = dest; sa.text_said = text_said; return kernel_ops->del_sa(&sa);}/* * Setup a pair of SAs. * */static boolsetup_half_ipsec_sa(struct state *st, bool inbound){ /* Build an inbound or outbound SA */ struct connection *c = st->st_connection; ip_subnet src, dst; ip_subnet src_client, dst_client; ipsec_spi_t inner_spi = 0; unsigned int proto = 0, satype = 0; bool replace; /* SPIs, saved for spigrouping or undoing, if necessary */ struct kernel_sa said[EM_MAXRELSPIS], *said_next = said; char text_said[SATOT_BUF]; int encapsulation; replace = inbound && (kernel_ops->get_spi != NULL); src.maskbits = 0; dst.maskbits = 0; if (inbound) { src.addr = c->spd.that.host_addr; dst.addr = c->spd.this.host_addr; src_client = c->spd.that.client; dst_client = c->spd.this.client; } else { src.addr = c->spd.this.host_addr, dst.addr = c->spd.that.host_addr; src_client = c->spd.this.client; dst_client = c->spd.that.client; } 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; } memset(said, 0, sizeof(said)); /* If we are tunnelling, set up IP in IP pseudo SA */ if (kernel_ops->inbound_eroute) { inner_spi = 256; proto = SA_IPIP; satype = SADB_SATYPE_UNSPEC; } else if (encapsulation == ENCAPSULATION_MODE_TUNNEL) { /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI * XXX FOR IP-in-IP ENCAPSULATION! */ ipsec_spi_t ipip_spi; /* Allocate an SPI for the tunnel. * Since our peer will never see this, * and it comes from its own number space, * it is purely a local implementation wart. */ { static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN; ipip_spi = htonl(++last_tunnel_spi); if (inbound) st->st_tunnel_in_spi = ipip_spi; else st->st_tunnel_out_spi = ipip_spi; } set_text_said(text_said , &c->spd.that.host_addr, ipip_spi, SA_IPIP); 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 = ipip_spi; said_next->satype = SADB_X_SATYPE_IPIP; said_next->text_said = text_said; if (!kernel_ops->add_sa(said_next, replace)) { DBG_log("add_sa tunnel failed"); goto fail; } said_next++; inner_spi = ipip_spi; proto = SA_IPIP; satype = SADB_X_SATYPE_IPIP; } /* set up IPCOMP SA, if any */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?