esp_output.c
来自「eCos操作系统源码」· C语言 代码 · 共 728 行 · 第 1/2 页
C
728 行
esp = mtod(md, struct esp *); } nxt = *nexthdrp; *nexthdrp = IPPROTO_ESP; switch (af) {#ifdef INET case AF_INET: if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len))) ip->ip_len = htons(ntohs(ip->ip_len) + esphlen); else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; } break;#endif#ifdef INET6 case AF_INET6: /* total packet length will be computed in ip6_output() */ break;#endif } } /* initialize esp header. */ esp->esp_spi = spi; if ((sav->flags & SADB_X_EXT_OLD) == 0) { struct newesp *nesp; nesp = (struct newesp *)esp; if (sav->replay->count == ~0) { if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) { /* XXX Is it noisy ? */ ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); stat->out_inval++; m_freem(m); return EINVAL; } } sav->replay->count++; /* * XXX sequence number must not be cycled, if the SA is * installed by IKE daemon. */ nesp->esp_seq = htonl(sav->replay->count); } { /* * find the last mbuf. make some room for ESP trailer. */#ifdef INET struct ip *ip = NULL;#endif size_t padbound; u_char *extend; int i; int randpadmax; if (algo->padbound) padbound = algo->padbound; else padbound = 4; /* ESP packet, including nxthdr field, must be length of 4n */ if (padbound < 4) padbound = 4; extendsiz = padbound - (plen % padbound); if (extendsiz == 1) extendsiz = padbound + 1; /* random padding */ switch (af) {#ifdef INET case AF_INET: randpadmax = ip4_esp_randpad; break;#endif#ifdef INET6 case AF_INET6: randpadmax = ip6_esp_randpad; break;#endif default: randpadmax = -1; break; } if (randpadmax < 0 || plen + extendsiz >= randpadmax) ; else { int n; /* round */ randpadmax = (randpadmax / padbound) * padbound; n = (randpadmax - plen + extendsiz) / padbound; if (n > 0) n = (random() % n) * padbound; else n = 0; /* * make sure we do not pad too much. * MLEN limitation comes from the trailer attachment * code below. * 256 limitation comes from sequential padding. * also, the 1-octet length field in ESP trailer imposes * limitation (but is less strict than sequential padding * as length field do not count the last 2 octets). */ if (extendsiz + n <= MLEN && extendsiz + n < 256) extendsiz += n; }#ifdef DIAGNOSTIC if (extendsiz > MLEN || extendsiz >= 256) panic("extendsiz too big in esp_output");#endif n = m; while (n->m_next) n = n->m_next; /* * if M_EXT, the external mbuf data may be shared among * two consequtive TCP packets, and it may be unsafe to use the * trailing space. */ if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) { extend = mtod(n, u_char *) + n->m_len; n->m_len += extendsiz; m->m_pkthdr.len += extendsiz; } else { struct mbuf *nn; MGET(nn, M_DONTWAIT, MT_DATA); if (!nn) { ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf", afnumber)); m_freem(m); error = ENOBUFS; goto fail; } extend = mtod(nn, u_char *); nn->m_len = extendsiz; nn->m_next = NULL; n->m_next = nn; n = nn; m->m_pkthdr.len += extendsiz; } switch (sav->flags & SADB_X_EXT_PMASK) { case SADB_X_EXT_PRAND: key_randomfill(extend, extendsiz); break; case SADB_X_EXT_PZERO: bzero(extend, extendsiz); break; case SADB_X_EXT_PSEQ: for (i = 0; i < extendsiz; i++) extend[i] = (i + 1) & 0xff; break; } /* initialize esp trailer. */ esptail = (struct esptail *) (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail)); esptail->esp_nxt = nxt; esptail->esp_padlen = extendsiz - 2; /* modify IP header (for ESP header part only) */ switch (af) {#ifdef INET case AF_INET: ip = mtod(m, struct ip *); if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len))) ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz); else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; } break;#endif#ifdef INET6 case AF_INET6: /* total packet length will be computed in ip6_output() */ break;#endif } } /* * pre-compute and cache intermediate key */ error = esp_schedule(algo, sav); if (error) { m_freem(m); stat->out_inval++; goto fail; } /* * encrypt the packet, based on security association * and the algorithm specified. */ if (!algo->encrypt) panic("internal error: no encrypt function"); if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) { /* m is already freed */ ipseclog((LOG_ERR, "packet encryption failure\n")); stat->out_inval++; error = EINVAL; goto fail; } /* * calculate ICV if required. */ if (!sav->replay) goto noantireplay; if (!sav->key_auth) goto noantireplay; if (sav->key_auth == SADB_AALG_NONE) goto noantireplay; { const struct ah_algorithm *aalgo; u_char authbuf[AH_MAXSUMSIZE]; struct mbuf *n; u_char *p; size_t siz;#ifdef INET struct ip *ip;#endif aalgo = ah_algorithm_lookup(sav->alg_auth); if (!aalgo) goto noantireplay; siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1); if (AH_MAXSUMSIZE < siz) panic("assertion failed for AH_MAXSUMSIZE"); if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) { ipseclog((LOG_ERR, "ESP checksum generation failure\n")); m_freem(m); error = EINVAL; stat->out_inval++; goto fail; } n = m; while (n->m_next) n = n->m_next; if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */ n->m_len += siz; m->m_pkthdr.len += siz; p = mtod(n, u_char *) + n->m_len - siz; } else { struct mbuf *nn; MGET(nn, M_DONTWAIT, MT_DATA); if (!nn) { ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output", afnumber)); m_freem(m); error = ENOBUFS; goto fail; } nn->m_len = siz; nn->m_next = NULL; n->m_next = nn; n = nn; m->m_pkthdr.len += siz; p = mtod(nn, u_char *); } bcopy(authbuf, p, siz); /* modify IP header (for ESP header part only) */ switch (af) {#ifdef INET case AF_INET: ip = mtod(m, struct ip *); if (siz < (IP_MAXPACKET - ntohs(ip->ip_len))) ip->ip_len = htons(ntohs(ip->ip_len) + siz); else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; } break;#endif#ifdef INET6 case AF_INET6: /* total packet length will be computed in ip6_output() */ break;#endif } }noantireplay: if (!m) { ipseclog((LOG_ERR, "NULL mbuf after encryption in esp%d_output", afnumber)); } else stat->out_success++; stat->out_esphist[sav->alg_enc]++; key_sa_recordxfer(sav, m); return 0;fail:#if 1 return error;#else panic("something bad in esp_output");#endif}#ifdef INETintesp4_output(m, isr) struct mbuf *m; struct ipsecrequest *isr;{ struct ip *ip; if (m->m_len < sizeof(struct ip)) { ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n")); m_freem(m); return 0; } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);}#endif /* INET */#ifdef INET6intesp6_output(m, nexthdrp, md, isr) struct mbuf *m; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr;{ if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n")); m_freem(m); return 0; } return esp_output(m, nexthdrp, md, isr, AF_INET6);}#endif /* INET6 */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?