bgp_tcpsig.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:13k
源码类别:

网络

开发平台:

Unix_Linux

  1. /* BGP TCP signature related functions
  2.    Copyright (C) 2004 Hiroki Nakano; Thanks to Okabe lab. (Kyoto University)
  3. This file is part of GNU Zebra.
  4. GNU Zebra is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8. GNU Zebra is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Zebra; see the file COPYING.  If not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. 02111-1307, USA.  */
  16. #include <zebra.h>
  17. #ifdef HAVE_OPENBSD_TCP_SIGNATURE
  18. #include <net/pfkeyv2.h>
  19. #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
  20. #include "log.h"
  21. #include "memory.h"
  22. #include "sockunion.h"
  23. #include "vty.h"
  24. #include "bgpd/bgpd.h"
  25. #include "bgpd/bgp_network.h"
  26. #include "bgpd/bgp_tcpsig.h"
  27. #ifdef HAVE_OPENBSD_TCP_SIGNATURE
  28. #define IOVEC_SIZE 20
  29. #define MAX_KEY_LEN 80
  30. #define SADBALIGN sizeof(u_int64_t)
  31. #define LENUNIT(x) ((x) / SADBALIGN)
  32. #define EXTLEN(x) (((struct sadb_ext *)(x))->sadb_ext_len * SADBALIGN)
  33. #define PADUP(x) (((x) + (SADBALIGN - 1)) & ~(SADBALIGN - 1))
  34. static u_int32_t bgp_pfkey_sadb_msg_seq = 1;
  35. static int bgp_pfkey_sd = -1;
  36. int bgp_pfkey_init(void);
  37. #define PUSH_IOVEC(base,len) ((*iovsizep) > 0 ? 
  38.       ((*iovp)->iov_base = (base), 
  39.                                (*iovp)->iov_len = (len), 
  40.                                (*iovp)++, 
  41.                                (*iovsizep)--) : 
  42.       ((*iovsizep) = -1))
  43. struct bgp_pfkey_sadb_msg {
  44.   struct sadb_msg header;
  45. };
  46. int
  47. bgp_pfkey_build_sadb_msg(u_int8_t mtype,
  48.  struct bgp_pfkey_sadb_msg *sp,
  49.  struct iovec **iovp, int *iovsizep)
  50. {
  51.   memset(sp, 0, sizeof(*sp));
  52.   sp->header.sadb_msg_version = PF_KEY_V2;
  53.   sp->header.sadb_msg_type = mtype;
  54.   sp->header.sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE;
  55.   sp->header.sadb_msg_len = LENUNIT(sizeof(sp->header));
  56.   sp->header.sadb_msg_seq = bgp_pfkey_sadb_msg_seq++;
  57.   sp->header.sadb_msg_pid = getpid();
  58.   PUSH_IOVEC(&sp->header, sizeof(sp->header));
  59.   
  60.   return sp->header.sadb_msg_len;
  61. }
  62. struct bgp_pfkey_sadb_sa {
  63.   struct sadb_sa header;
  64. };
  65. int
  66. bgp_pfkey_build_sadb_sa(u_int32_t spi,
  67. struct bgp_pfkey_sadb_sa *sp,
  68. struct iovec **iovp, int *iovsizep)
  69. {
  70.   memset(sp, 0, sizeof(*sp));
  71.   sp->header.sadb_sa_len = LENUNIT(sizeof(sp->header));
  72.   sp->header.sadb_sa_exttype = SADB_EXT_SA;
  73.   sp->header.sadb_sa_spi = spi;
  74.   sp->header.sadb_sa_replay = 0;
  75.   sp->header.sadb_sa_state = SADB_SASTATE_MATURE;
  76.   sp->header.sadb_sa_auth = 0;
  77.   sp->header.sadb_sa_encrypt = 0;
  78.   PUSH_IOVEC(&sp->header, sizeof(sp->header));
  79.   
  80.   return sp->header.sadb_sa_len;
  81. }
  82. struct bgp_pfkey_sadb_address {
  83.   struct sadb_address header;
  84.   struct sockaddr_storage ss;
  85. };
  86. int
  87. bgp_pfkey_build_sadb_address(union sockunion *su,
  88.      struct bgp_pfkey_sadb_address *sp,
  89.      struct iovec **iovp, int *iovsizep)
  90. {
  91.   int paddedsslen;
  92.   memset(sp, 0, sizeof(*sp));
  93.   switch (su->sa.sa_family) {
  94.   case AF_INET:
  95.     ((struct sockaddr_in *)&sp->ss)->sin_family = AF_INET;
  96.     ((struct sockaddr_in *)&sp->ss)->sin_len = sizeof(struct sockaddr_in);
  97.     ((struct sockaddr_in *)&sp->ss)->sin_addr = su->sin.sin_addr;
  98.     break;
  99.   case AF_INET6:
  100.     ((struct sockaddr_in6 *)&sp->ss)->sin6_family = AF_INET6;
  101.     ((struct sockaddr_in6 *)&sp->ss)->sin6_len = sizeof(struct sockaddr_in6);
  102.     ((struct sockaddr_in6 *)&sp->ss)->sin6_addr = su->sin6.sin6_addr;
  103.     break;
  104.   default:
  105.     return -1;
  106.   }
  107.   paddedsslen = PADUP(((struct sockaddr *)&sp->ss)->sa_len);
  108.   sp->header.sadb_address_len = LENUNIT(sizeof(sp->header) + paddedsslen);
  109.   sp->header.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
  110.   PUSH_IOVEC(&sp->header, sizeof(sp->header));
  111.   PUSH_IOVEC(&sp->ss, paddedsslen);
  112.   
  113.   return sp->header.sadb_address_len;
  114. }
  115. struct bgp_pfkey_sadb_key {
  116.   struct sadb_key header;
  117.   char keybuf[PADUP(MAX_KEY_LEN)];
  118. };
  119. int
  120. bgp_pfkey_build_sadb_key(char *key, int keylen,
  121.  struct bgp_pfkey_sadb_key *sp,
  122.  struct iovec **iovp, int *iovsizep)
  123. {
  124.   int paddedkeylen;
  125.   if (keylen < 0 || keylen > MAX_KEY_LEN)
  126.     return -1; 
  127.   memset(sp, 0, sizeof(*sp));
  128.   memcpy(sp->keybuf, key, keylen);
  129.   paddedkeylen = PADUP(keylen);
  130.   sp->header.sadb_key_len = LENUNIT(sizeof(sp->header) + paddedkeylen);
  131.   sp->header.sadb_key_exttype = SADB_EXT_KEY_AUTH;
  132.   sp->header.sadb_key_bits = 8 * keylen;
  133.   PUSH_IOVEC(&sp->header, sizeof(sp->header));
  134.   PUSH_IOVEC(sp->keybuf, paddedkeylen);
  135.   return sp->header.sadb_key_len;
  136. }
  137. struct bgp_pfkey_sadb_spirange {
  138.   struct sadb_spirange header;
  139. };
  140. int
  141. bgp_pfkey_build_sadb_spirange(struct bgp_pfkey_sadb_spirange *sp,
  142.       struct iovec **iovp, int *iovsizep)
  143. {
  144.   memset(sp, 0, sizeof(*sp));
  145.   sp->header.sadb_spirange_len = LENUNIT(sizeof(sp->header));
  146.   sp->header.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
  147.   sp->header.sadb_spirange_min = 0x100;
  148.   sp->header.sadb_spirange_max = 0xffffffff;
  149.   PUSH_IOVEC(&sp->header, sizeof(sp->header));
  150.   
  151.   return sp->header.sadb_spirange_len;
  152. }
  153. int
  154. bgp_pfkey_write(int fd, struct iovec *iov, int iovcnt)
  155. {
  156.   int i, len, rlen;
  157.   len = 0;
  158.   for (i = 0; i < iovcnt; i++)
  159.     len += iov[i].iov_len;
  160.   rlen = writev(fd, iov, iovcnt);
  161.   if (rlen == -1)
  162.     {
  163.       zlog_err("pfkey writev: %s", strerror(errno));
  164.       return -1;
  165.     }
  166.   else if (rlen != len)
  167.     {
  168.       zlog_err("pfkey writev: len=%d ret=%d", len, rlen);
  169.       return -1;
  170.     }
  171.  
  172.   return 0;
  173. }
  174. int
  175. bgp_pfkey_read(int fd, void **bufp, int *lenp)
  176. {
  177.   struct sadb_msg smsg;
  178.   void *msgbuf;
  179.   int msglen, rlen;
  180.   rlen = recv(fd, &smsg, sizeof(smsg), MSG_PEEK);
  181.   if (rlen == -1)
  182.     {
  183.       zlog_err("pfkey recv: %s", strerror(errno));
  184.       return -1;
  185.     }
  186.   if (rlen != sizeof(smsg))
  187.     {
  188.       zlog_err("pfkey recv: len=%d ret=%d", sizeof(smsg), rlen);
  189.       return -1;
  190.     }
  191.   if (smsg.sadb_msg_errno != 0 ||
  192.       smsg.sadb_msg_errno != ESRCH)
  193.     {
  194.       zlog_err("pfkey read msg: %s", strerror(smsg.sadb_msg_errno));
  195.       read(fd, &smsg, sizeof(smsg)); /* get rid of error message */
  196.       return -1;
  197.     }
  198.   msglen = smsg.sadb_msg_len * SADBALIGN;
  199.   msgbuf = XMALLOC(MTYPE_TMP, msglen);
  200.   rlen = read(fd, msgbuf, msglen);
  201.   if (rlen == -1)
  202.     {
  203.       zlog_err("pfkey read: %s", strerror(errno));
  204.       XFREE(MTYPE_TMP, msgbuf);
  205.       return -1;
  206.     }
  207.   if (rlen != msglen)
  208.     {
  209.       zlog_err("pfkey read: len=%d ret=%d", msglen, rlen);
  210.       XFREE(MTYPE_TMP, msgbuf);
  211.       return -1;
  212.     }
  213.   *bufp = msgbuf;
  214.   *lenp = msglen;
  215.   return 0;
  216. }
  217. int
  218. bgp_pfkey_search_ext(void *buf, u_int16_t exttype, void **prevp)
  219. {
  220.   struct sadb_msg *msg;
  221.   struct sadb_ext *p, *last;
  222.   u_int32_t len;
  223.   msg = buf;
  224.   len = msg->sadb_msg_len * SADBALIGN;
  225.   last = (struct sadb_ext *)(((u_int8_t *)msg) + len);
  226.   p = *prevp ? *prevp : (struct sadb_ext *)(msg + 1);
  227.   while ((u_int8_t *)p < (u_int8_t *)last)
  228.     {
  229.       if (p->sadb_ext_type == exttype)
  230. {
  231.   *prevp = p;
  232.   return 0; /* found */
  233. }
  234.       p = (struct sadb_ext *)(((u_int8_t *)p) + EXTLEN(p));
  235.     }
  236.   return -1; /* not found */
  237. }
  238. int
  239. bgp_pfkey_getspi(union sockunion *src, union sockunion *dst, u_int32_t *spip)
  240. {
  241.   struct iovec iovbuf[IOVEC_SIZE], *iov;
  242.   int iovcnt, iovrest;
  243.   struct bgp_pfkey_sadb_msg s_msg;
  244.   struct bgp_pfkey_sadb_spirange s_spirange;
  245.   struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr;
  246.   int len;
  247.   void *buf;
  248.   int buflen;
  249.   struct sadb_sa *ext_sa;
  250.   if (bgp_pfkey_sd == -1)
  251.     {
  252.       bgp_pfkey_init();
  253.       if (bgp_pfkey_sd == -1)
  254. return -1;
  255.     }
  256.   iov = iovbuf;
  257.   iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]);
  258.   len = bgp_pfkey_build_sadb_msg(SADB_GETSPI, &s_msg, &iov, &iovrest);
  259.   len += bgp_pfkey_build_sadb_spirange(&s_spirange, &iov, &iovrest);
  260.   len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest);
  261.   len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest);
  262.   s_msg.header.sadb_msg_len = len;
  263.   iovcnt -= iovrest;
  264.   if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0)
  265.     {
  266.       zlog_err("pfkey getspi: fail to write request");
  267.       return -1;
  268.     }
  269.   if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0)
  270.     {
  271.       zlog_err("pfkey getspi: fail to read reply");
  272.       return -1;
  273.     }
  274.   if (bgp_pfkey_search_ext(buf, SADB_EXT_SA, (void **)&ext_sa) != 0)
  275.     {
  276.       zlog_err("pfkey getspi: no SA extention");
  277.       XFREE(MTYPE_TMP, buf);
  278.       return -1;
  279.     }
  280.   *spip = ext_sa->sadb_sa_spi;
  281.   XFREE(MTYPE_TMP, buf);
  282.   return 0;
  283. }
  284. int
  285. bgp_pfkey_update(u_int32_t spi, union sockunion *src, union sockunion *dst,
  286.  char *key)
  287. {
  288.   struct iovec iovbuf[IOVEC_SIZE], *iov;
  289.   int iovcnt, iovrest;
  290.   struct bgp_pfkey_sadb_msg s_msg;
  291.   struct bgp_pfkey_sadb_sa s_sa;
  292.   struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr;
  293.   struct bgp_pfkey_sadb_key s_key;
  294.   int len;
  295.   void *buf;
  296.   int buflen;
  297.   if (bgp_pfkey_sd == -1)
  298.     {
  299.       bgp_pfkey_init();
  300.       if (bgp_pfkey_sd == -1)
  301. return -1;
  302.     }
  303.   iov = iovbuf;
  304.   iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]);
  305.   len = bgp_pfkey_build_sadb_msg(SADB_UPDATE, &s_msg, &iov, &iovrest);
  306.   len += bgp_pfkey_build_sadb_sa(spi, &s_sa, &iov, &iovrest);
  307.   len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest);
  308.   len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest);
  309.   len += bgp_pfkey_build_sadb_key(key, strlen(key), &s_key, &iov, &iovrest);
  310.   s_msg.header.sadb_msg_len = len;
  311.   iovcnt -= iovrest;
  312.   if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0)
  313.     {
  314.       zlog_err("pfkey update: fail to write request");
  315.       return -1;
  316.     }
  317.   if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0)
  318.     {
  319.       zlog_err("pfkey update: fail to read reply");
  320.       return -1;
  321.     }
  322.   XFREE(MTYPE_TMP, buf);
  323.   return 0;
  324. }
  325. int
  326. bgp_pfkey_delete(u_int32_t spi, union sockunion *src, union sockunion *dst)
  327. {
  328.   struct iovec iovbuf[IOVEC_SIZE], *iov;
  329.   int iovcnt, iovrest;
  330.   struct bgp_pfkey_sadb_msg s_msg;
  331.   struct bgp_pfkey_sadb_sa s_sa;
  332.   struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr;
  333.   int len;
  334.   void *buf;
  335.   int buflen;
  336.   if (bgp_pfkey_sd == -1)
  337.     {
  338.       bgp_pfkey_init();
  339.       if (bgp_pfkey_sd == -1)
  340. return -1;
  341.     }
  342.   iov = iovbuf;
  343.   iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]);
  344.   len = bgp_pfkey_build_sadb_msg(SADB_DELETE, &s_msg, &iov, &iovrest);
  345.   len += bgp_pfkey_build_sadb_sa(spi, &s_sa, &iov, &iovrest);
  346.   len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest);
  347.   len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest);
  348.   s_msg.header.sadb_msg_len = len;
  349.   iovcnt -= iovrest;
  350.   if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0)
  351.     {
  352.       zlog_err("pfkey delete: fail to write request");
  353.       return -1;
  354.     }
  355.   if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0)
  356.     {
  357.       zlog_err("pfkey delete: fail to read reply");
  358.       return -1;
  359.     }
  360.   XFREE(MTYPE_TMP, buf);
  361.   return 0;
  362. }
  363. int
  364. bgp_pfkey_init(void)
  365. {
  366.   bgp_pfkey_sd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
  367.   if (bgp_pfkey_sd == -1)
  368.     {
  369.       zlog_warn("pfkey socket: %s", strerror(errno));
  370.       return -1;
  371.     }
  372.   return 0;
  373. }
  374. /*----------------------------------------------------------------*/
  375. int
  376. bgp_tcpsig_pfkey_set(struct peer *p)
  377. {
  378.   if (!p->update_source)
  379.     return -1;
  380.   
  381.   if (p->spi_out == 0)
  382.     if (bgp_pfkey_getspi(p->update_source, &p->su, &p->spi_out) != 0)
  383.       return -1;
  384.   if (bgp_pfkey_update(p->spi_out,
  385.  p->update_source, &p->su, p->password) != 0)
  386.     return -1;
  387.   if (p->spi_in == 0)
  388.     if (bgp_pfkey_getspi(&p->su, p->update_source, &p->spi_in) != 0)
  389.       return -1;
  390.   if (bgp_pfkey_update(p->spi_in,
  391.  &p->su, p->update_source, p->password) != 0)
  392.     return -1;
  393.   
  394.   return 0;
  395. }
  396. int
  397. bgp_tcpsig_pfkey_unset(struct peer *p)
  398. {
  399.   if (!p->update_source)
  400.     return -1;
  401.   
  402.   if (p->spi_out != 0)
  403.     if (bgp_pfkey_delete(p->spi_out, p->update_source, &p->su) != 0)
  404.       return -1;
  405.   p->spi_out = 0;
  406.   if (p->spi_in != 0)
  407.     if (bgp_pfkey_delete(p->spi_in, &p->su, p->update_source) != 0)
  408.       return -1;
  409.   p->spi_in = 0;
  410.   
  411.   return 0;
  412. }
  413. #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
  414. /*----------------------------------------------------------------*/
  415. #ifdef HAVE_LINUX_TCP_SIGNATURE
  416. int
  417. bgp_tcpsig_set (int sock, struct peer *peer)
  418. {
  419.   struct tcp_rfc2385_cmd cmd;
  420.   int ret;
  421.   if (sockunion_family (&peer->su) != AF_INET)
  422.     return 0; /* XXX */
  423.   cmd.command = TCP_MD5_AUTH_ADD;
  424.   cmd.address = peer->su.sin.sin_addr.s_addr;
  425.   cmd.keylen = strlen (peer->password);
  426.   cmd.key = peer->password;
  427.   ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
  428.   return ret;
  429. }
  430. #endif /* HAVE_LINUX_TCP_SIGNATURE */
  431. #ifdef HAVE_OPENBSD_TCP_SIGNATURE
  432. int
  433. bgp_tcpsig_set (int sock, struct peer *peer)
  434. {
  435.   int cmd = 1;
  436.   int ret = 0;
  437.   if (peer)
  438.     ret = bgp_tcpsig_pfkey_set(peer);
  439.   
  440.   if (ret == 0 && sock != -1)
  441.     ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &cmd, sizeof cmd);
  442.   return ret;
  443. }
  444. #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
  445. #ifdef HAVE_LINUX_TCP_SIGNATURE
  446. int
  447. bgp_tcpsig_unset (int sock, struct peer *peer)
  448. {
  449.   struct tcp_rfc2385_cmd cmd;
  450.   int ret;
  451.   if (sockunion_family (&peer->su) != AF_INET)
  452.     return 0; /* XXX */
  453.   cmd.command = TCP_MD5_AUTH_DEL;
  454.   cmd.address = peer->su.sin.sin_addr.s_addr;
  455.   cmd.keylen = strlen (peer->password);
  456.   cmd.key = peer->password;
  457.   ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
  458.   return ret;
  459. }
  460. #endif /* HAVE_LINUX_TCP_SIGNATURE */
  461. #ifdef HAVE_OPENBSD_TCP_SIGNATURE
  462. int
  463. bgp_tcpsig_unset (int sock, struct peer *peer)
  464. {
  465.   return bgp_tcpsig_pfkey_unset(peer);
  466. }
  467. #endif /* HAVE_OPENBSD_TCP_SIGNATURE */