Add send (rfc3971 implementation)
authorFlorian Fainelli <florian@openwrt.org>
Tue, 21 Oct 2008 17:03:18 +0000 (17:03 +0000)
committerFlorian Fainelli <florian@openwrt.org>
Tue, 21 Oct 2008 17:03:18 +0000 (17:03 +0000)
SVN-Revision: 13020

ipv6/send/Makefile [new file with mode: 0644]
ipv6/send/patches/001-libnetfilter_queue_update.patch [new file with mode: 0644]
ipv6/send/patches/002-handle_max_bits_conf.patch [new file with mode: 0644]
ipv6/send/patches/003-keysig_8bytes_alignment.patch [new file with mode: 0644]
ipv6/send/patches/004-always_link_with_ncurses.patch [new file with mode: 0644]

diff --git a/ipv6/send/Makefile b/ipv6/send/Makefile
new file mode 100644 (file)
index 0000000..2409abf
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# $Id: $
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=send
+PKG_VERSION:=0.2-4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)d_$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://rfc.1924.fr/debian-mobisend/pool/main/s/sendd/
+PKG_MD5SUM:=57907178cad20fe3a21e2e449de1dc13
+PKG_BUILD_DIR:=$(BUILD_DIR)/sendd-0.2
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/send
+  SECTION:=ipv6
+  CATEGORY:=IPv6
+  TITLE:=Secure Neighbor Discovery implementation
+  URL:=http://rfc.1924.fr/debian-mobisend.html
+  DEPENDS:=+kmod-ipv6 +ip6tables +libnetfilter-queue +libopenssl +libreadline +libncurses
+endef
+
+define Package/send/description
+       DoCoMo's Open Source SEND project provides an implementation of RFC 3971
+       Secure Neighbor Discovery (SEND). SEND cryptographically secures the
+       IPv6 neighbor discovery protocol, countering the threats discussed in
+       RFC 3756 (IPv6 Neighbor Discovery (ND) Trust Models and Threats).
+endef
+
+define Package/send/conffiles
+/etc/sendd/sendd.conf
+/etc/sendd/params.conf
+endef
+
+MAKE_FLAGS += \
+       CC="$(TARGET_CC)" \
+       CFLAGS="$(TARGET_CFLAGS) -I$(STAGING_DIR)/usr/include/libnetfilter_queue -I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include" \
+       LDFLAGS="$(TARGET_LDFLAGS) -lnfnetlink" \
+
+define Package/send/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/sendd/sendd $(1)/usr/sbin/
+       $(INSTALL_DIR) $(1)/etc/sendd/
+       $(INSTALL_CONF) $(PKG_BUILD_DIR)/examples/sendd.conf $(1)/etc/sendd/
+       $(INSTALL_CONF) $(PKG_BUILD_DIR)/examples/params.conf $(1)/etc/sendd/
+endef
+
+$(eval $(call BuildPackage,send))
diff --git a/ipv6/send/patches/001-libnetfilter_queue_update.patch b/ipv6/send/patches/001-libnetfilter_queue_update.patch
new file mode 100644 (file)
index 0000000..a06c6ae
--- /dev/null
@@ -0,0 +1,396 @@
+Index: sendd-0.2/Makefile.config
+===================================================================
+--- sendd-0.2.orig/Makefile.config     2008-05-27 16:53:49.238160776 +0200
++++ sendd-0.2/Makefile.config  2008-05-27 16:53:52.866156255 +0200
+@@ -19,7 +19,7 @@
+ #CC=gcc-4.0
+ # Where to install
+-prefix=/usr
++prefix=$(DESTDIR)/usr
+ # Set to "y" to build MT versions of sendd and cgatool
+ USE_THREADS=n
+Index: sendd-0.2/README
+===================================================================
+--- sendd-0.2.orig/README      2008-05-27 16:53:49.246168775 +0200
++++ sendd-0.2/README   2008-05-27 16:53:52.866156255 +0200
+@@ -20,7 +20,7 @@
+   o CONFIG_NETFILTER, CONFIG_IPV6, CONFIG_IP6_NF_QUEUE, CONFIG_IP6_NF_IPTABLES,
+     CONFIG_IP6_NF_FILTER enabled in your kernel config.
+   o netfilter ip6tables command
+-  o netfilter libipq development library and headers
++  o netfilter libnetfilter_queue development library and headers
+ FreeBSD:
+   o NETGRAPH, NETGRAPH_BPF, NETGRAPH_ETHER, NETGRAPH_SOCKET enabled in
+Index: sendd-0.2/cgatool/Makefile
+===================================================================
+--- sendd-0.2.orig/cgatool/Makefile    2008-05-27 16:53:49.278164104 +0200
++++ sendd-0.2/cgatool/Makefile 2008-05-27 16:53:52.866156255 +0200
+@@ -25,7 +25,7 @@
+ ifeq ($(USE_CONSOLE),y)
+ ifeq ($(USE_READLINE),y)
+-LDLIBS += -lreadline -lncurses
++LDLIBS += -lreadline
+ endif
+ endif
+Index: sendd-0.2/sendd/Makefile
+===================================================================
+--- sendd-0.2.orig/sendd/Makefile      2008-05-27 16:53:49.286173430 +0200
++++ sendd-0.2/sendd/Makefile   2008-05-27 16:53:52.878156241 +0200
+@@ -37,7 +37,7 @@
+ ifeq ($(USE_CONSOLE),y)
+ ifeq ($(USE_READLINE),y)
+-LDLIBS += -lreadline -lncurses
++LDLIBS += -lreadline
+ endif
+ endif
+Index: sendd-0.2/sendd/os-linux/Makefile
+===================================================================
+--- sendd-0.2.orig/sendd/os-linux/Makefile     2008-05-27 16:53:49.294197424 +0200
++++ sendd-0.2/sendd/os-linux/Makefile  2008-05-27 16:53:52.910156597 +0200
+@@ -1,23 +1,5 @@
+ OBJS += os/addr.o os/ipq.o os/rand.o os/snd_linux.o
+-OSLIBS= -ldl -lipq
++OSLIBS= -lnetfilter_queue
+-OSEXTRA= os/sendd os/snd_upd_fw
+-
+-ETCINIT= /etc/init.d
+-EXTRAINSTALL= $(ETCINIT)/sendd $(ETCINIT)/snd_upd_fw $(ETCINIT)/snd_fw_functions.sh
+-EXTRAUNINSTALL=$(EXTRAINSTALL)
+-EXTRACLEAN= os/sendd os/snd_upd_fw os/snd_fw_functions.sh
+-
+-$(ETCINIT)/%: os/%
+-      install $< $@
+-
+-os/%: os/%.in
+-      sed "s/@etcinit@/\/etc\/init.d/g" $< > $@
+-
+-os/%: os/%.in2
+-      @./os/find_ip6tables.sh
+-
+-# Sometimes libipq.h is installed in include/libipq.h, other times it is
+-# installed in include/libipq/libipq.h. This rule helps cpp to find it.
+-os/ipq.o: CPPFLAGS += -I/usr/include/libipq -I/usr/local/include/libipq
++os/ipq.o: CPPFLAGS += -I/usr/include/libnetfilter_queue
+Index: sendd-0.2/sendd/os-linux/ipq.c
+===================================================================
+--- sendd-0.2.orig/sendd/os-linux/ipq.c        2008-05-27 16:53:49.306181136 +0200
++++ sendd-0.2/sendd/os-linux/ipq.c     2008-05-27 16:55:57.602168158 +0200
+@@ -33,7 +33,7 @@
+ #include <sys/select.h>
+ #include <netinet/in.h>
+ #include <linux/netfilter.h>
+-#include <libipq.h>
++#include <libnetfilter_queue.h>
+ #include "config.h"
+ #include <applog.h>
+@@ -42,122 +42,170 @@
+ #include "../sendd_local.h"
+ #include "snd_linux.h"
+-static struct ipq_handle *qh;
+-
+ extern unsigned if_nametoindex(const char *);
+-static inline void
+-process_pkt(ipq_packet_msg_t *pkt, struct sbuff *b)
+-{
++struct nfq_handle *h = NULL;
++struct nfq_q_handle *qh = NULL;
++
++/* This is the default queue number used in our init script */
++#define SND_DEFAULT_NFQUEUE_NUMBER 13
++
++/* The sbuff is must be made available to the callback function that will
++   handle the packet */
++struct callback_data {
++      struct sbuff *b;
++};
++
++struct callback_data process_pkt_data;
++
++/* nfqueue callback */
++static int process_pkt(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
++                     struct nfq_data *nfa, void *data)
++{
++      struct callback_data * d = (struct callback_data *)data;
++      struct nfqnl_msg_packet_hdr *ph;
++      struct sbuff *b = d->b;
++      char *pkt_data;
+       int in, ifidx;
+-      b->data = pkt->payload;
+-      b->len = pkt->data_len;
++      b->len = nfq_get_payload(nfa, &pkt_data);
++      if (b->len == -1) {
++              applog(LOG_ERR, "%s: nfq_get_payload() failed.", __FUNCTION__);
++              return 0;
++      }
++      b->data = (unsigned char *)pkt_data;
+-      if (*(pkt->indev_name)) {
++      if ((ifidx = nfq_get_indev(nfa)) && ifidx != 0)
+               in = 1;
+-              ifidx = if_nametoindex(pkt->indev_name);
+-      } else if (*(pkt->outdev_name)) {
++      else if ((ifidx = nfq_get_outdev(nfa)) && ifidx != 0)
+               in = 0;
+-              ifidx = if_nametoindex(pkt->outdev_name);
+-      } else {
++      else {
+               applog(LOG_ERR, "%s: pkt has neither indev nor outdev",
+                      __FUNCTION__);
+               snd_put_buf(b);
+-              return;
++              return 0;
+       }
+-      snd_recv_pkt(b, ifidx, in, pkt);
+-}
++      /* Grab packet header to get its id later */
++      ph = nfq_get_msg_packet_hdr(nfa); /* FIXME Check return value */
+-static void
+-ipq_recv_pkt(void)
+-{
+-      int r;
+-      struct sbuff *b = snd_get_buf();
++      snd_recv_pkt(b, ifidx, in, (void *)ph);
+-      if (b == NULL) {
+-              return;
+-      }
+-      if ((r = ipq_read(qh, b->head, b->rem, -1)) < 0) {
+-              applog(LOG_ERR, "%s: ipq_read(): %s", __FUNCTION__,
+-                     ipq_errstr());
+-              goto fail;
+-      } else if (r == 0) {
+-              /* timeout */
+-              goto fail;
+-      }
+-
+-      switch ((r = ipq_message_type(b->head))) {
+-      case NLMSG_ERROR:
+-              applog(LOG_ERR, "%s: nlmsg error: %s", __FUNCTION__,
+-                     strerror(ipq_get_msgerr(b->head)));
+-              goto fail;
+-      case IPQM_PACKET:
+-              process_pkt(ipq_get_packet(b->head), b);
+-              return;
+-      default:
+-              break;
+-      }
+-
+-fail:
+-      snd_put_buf(b);
++      return 1;
+ }
+ void
+-linux_ipq_add_fds(fd_set *fds, int *maxfd)
++linux_nfq_add_fds(fd_set *fds, int *maxfd)
+ {
+-      FD_SET(qh->fd, fds);
+-      *maxfd = sendd_max(*maxfd, qh->fd);
++      int fd = nfnl_fd(nfq_nfnlh(h));
++
++      FD_SET(fd, fds);
++      *maxfd = sendd_max(*maxfd, fd);
+ }
+ void
+-linux_ipq_dispatch_fds(fd_set *fds)
++linux_nfq_dispatch_fds(fd_set *fds)
+ {
+-      if (FD_ISSET(qh->fd, fds)) {
+-              ipq_recv_pkt();
++      int fd = nfnl_fd(nfq_nfnlh(h));
++      int r;
++
++      if (FD_ISSET(fd, fds)) {
++              struct sbuff *b = snd_get_buf();
++
++              if (b == NULL) {
++                      return;
++              }
++
++              if ((r = recv(fd, b->head, b->rem, 0)) && r <= 0) {
++                      if (r < 0) /* not a timeout */
++                              applog(LOG_ERR, "%s: recv failed.",
++                                     __FUNCTION__);
++                      snd_put_buf(b);
++                      return;
++              }
++
++              process_pkt_data.b = b; /* make sbuff available to
++                                         callback function */
++              nfq_handle_packet(h, (char *)b->head, r);
+       }
+ }
+ void
+ os_specific_deliver_pkt(void *p, struct sbuff *b, int drop, int changed)
+ {
+-      ipq_packet_msg_t *pkt = p;
+-      void *newpkt = NULL;
++      struct nfqnl_msg_packet_hdr *ph = (struct nfqnl_msg_packet_hdr *)p;
++      unsigned char *newpkt = NULL;
+       int plen = 0;
++      uint32_t id = 0;
++
++      if (ph)
++              id = ntohl(ph->packet_id);
+       if (changed && !drop) {
+-              newpkt = sbuff_data(b);
++              newpkt = (unsigned char *)b->data;
+               plen = b->len;
+       }
+-      ipq_set_verdict(qh, pkt->packet_id, drop ? NF_DROP : NF_ACCEPT,
+-                      plen, newpkt);
++      nfq_set_verdict(qh, id, drop ? NF_DROP : NF_ACCEPT, plen, newpkt);
+       snd_put_buf(b);
+ }
+ int
+-linux_ipq_init(void)
++linux_nfq_init(void)
+ {
+-      if ((qh = ipq_create_handle(0, PF_INET6)) == NULL) {
+-              applog(LOG_ERR, "%s: ipq_create_handle() failed: %s",
+-                     __FUNCTION__, ipq_errstr());
+-              return (-1);
+-      }
+-      if (ipq_set_mode(qh, IPQ_COPY_PACKET, SND_MAX_PKT) < 0) {
+-              applog(LOG_ERR, "%s: ipq_set_mode() failed: %s",
+-                     __FUNCTION__, ipq_errstr());
+-              if (errno == ECONNREFUSED) {
+-                      applog(LOG_ERR, "%s: perhaps you need to modprobe "
+-                             "ip6_queue?", __FUNCTION__);
+-              }
+-              return (-1);
++      struct nfnl_handle *nh;
++      u_int16_t nfqueue_num = SND_DEFAULT_NFQUEUE_NUMBER;
++
++      /* Get netfilter queue connection handle */
++      h = nfq_open();
++      if (!h) {
++              applog(LOG_ERR, "%s: nfq_open() failed.", __FUNCTION__);
++              return -1;
++      }
++
++      /* Unbinding existing nfqueue handlers for AF_INET6. We ignore the
++         return value: http://www.spinics.net/lists/netfilter/msg42063.html.
++         Note that this call is required, otherwise, nfq_bind_pf() fails. */
++      nfq_unbind_pf(h, PF_INET6);
++
++      if (nfq_bind_pf(h, PF_INET6) < 0) {
++              applog(LOG_ERR, "%s: nfq_bind_pf failed.\n", __FUNCTION__);
++              return -1;
++      }
++
++      /* Binding this socket to queue number nfqueue_num and installing
++         our packet handler */
++      qh = nfq_create_queue(h, nfqueue_num,
++                            (nfq_callback *) &process_pkt,
++                            (void *)&process_pkt_data);
++      if (!qh) {
++              applog(LOG_ERR, "%s: nfq_create_queue() failed.\n",
++                     __FUNCTION__);
++              return -1;
++      }
++
++      /* Asking for entire copy of queued packets */
++      if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { /* XXX was SND_MAX_PKT */
++              fprintf(stderr, "nfq_set_mode() failed.\n");
++              return -1;
+       }
+-      return (0);
++
++      /* XXX - Check if we have an interest in setting queue length */
++
++      /* The netlink handle associated with our queue connection handle */
++      nh = nfq_nfnlh(h);
++
++      return 0;
+ }
+ void
+-linux_ipq_fini(void)
++linux_nfq_fini(void)
+ {
+-      ipq_destroy_handle(qh);
++      /* Remove the binding for our queue handler*/
++      if (qh != NULL)
++              nfq_destroy_queue(qh);
++
++      /* Close connection associated with our connection handler */
++      if (h != NULL)
++              nfq_close(h);
+ }
+Index: sendd-0.2/sendd/os-linux/snd_linux.c
+===================================================================
+--- sendd-0.2.orig/sendd/os-linux/snd_linux.c  2008-05-27 16:53:49.314164060 +0200
++++ sendd-0.2/sendd/os-linux/snd_linux.c       2008-05-27 16:53:52.914160667 +0200
+@@ -40,13 +40,13 @@
+ void
+ os_specific_add_fds(fd_set *fds, int *maxfd)
+ {
+-      linux_ipq_add_fds(fds, maxfd);
++      linux_nfq_add_fds(fds, maxfd);
+ }
+ void
+ os_specific_dispatch_fds(fd_set *fds)
+ {
+-      linux_ipq_dispatch_fds(fds);
++      linux_nfq_dispatch_fds(fds);
+ }
+ int
+@@ -59,7 +59,7 @@
+ os_specific_init(void)
+ {
+       if (linux_rand_init() < 0 ||
+-          linux_ipq_init() < 0) {
++          linux_nfq_init() < 0) {
+               return (-1);
+       }
+       return (0);
+@@ -68,6 +68,6 @@
+ void
+ os_specific_fini(void)
+ {
+-      linux_ipq_fini();
++      linux_nfq_fini();
+       linux_rand_fini();
+ }
+Index: sendd-0.2/sendd/os-linux/snd_linux.h
+===================================================================
+--- sendd-0.2.orig/sendd/os-linux/snd_linux.h  2008-05-27 16:53:49.330169232 +0200
++++ sendd-0.2/sendd/os-linux/snd_linux.h       2008-05-27 16:53:52.914160667 +0200
+@@ -33,10 +33,10 @@
+ #ifndef       _SEND_LINUX_H
+ #define       _SEND_LINUX_H
+-extern void linux_ipq_add_fds(fd_set *, int *);
+-extern void linux_ipq_dispatch_fds(fd_set *);
+-extern int linux_ipq_init(void);
+-extern void linux_ipq_fini(void);
++extern void linux_nfq_add_fds(fd_set *, int *);
++extern void linux_nfq_dispatch_fds(fd_set *);
++extern int linux_nfq_init(void);
++extern void linux_nfq_fini(void);
+ extern void linux_rand_fini(void);
+ extern int linux_rand_init(void);
diff --git a/ipv6/send/patches/002-handle_max_bits_conf.patch b/ipv6/send/patches/002-handle_max_bits_conf.patch
new file mode 100644 (file)
index 0000000..ad45ea5
--- /dev/null
@@ -0,0 +1,59 @@
+This patch allows one to specify a maximum number of bits
+for the CGA and RSA key size. RFC specifies that an implementation
+may optionnaly honor this setting (5.1.3). This is particularly
+useful on embedded systems where both the entropy and the processing
+power are limited.
+
+Index: sendd-0.2/sendd/config.c
+===================================================================
+diff -urN sendd-0.2/sendd/config.c sendd-0.2.new/sendd/config.c
+--- sendd-0.2/sendd/config.c   2008-04-18 16:21:46.000000000 +0200
++++ sendd-0.2.new/sendd/config.c       2008-09-09 15:41:11.000000000 +0200
+@@ -82,6 +82,7 @@
+       SND_CFS(snd_cga_params, NULL, 1),
+       SND_CFIB(snd_full_secure, 1, 0),
+       SND_CFII(snd_min_key_bits, 1024, "bits", 0),
++      SND_CFII(snd_max_key_bits, 2048, "bits", 0),
+       SND_CFII(snd_nonce_cache_gc_intvl, 2, "seconds", 0),
+       SND_CFII(snd_pfx_cache_gc_intvl, 40, "seconds", 0),
+       SND_CFS(snd_pkixip_conf, NULL, 0),
+Index: sendd-0.2/sendd/sig_rfc3971.c
+===================================================================
+diff -urN sendd-0.2/sendd/sig_rfc3971.c sendd-0.2.new/sendd/sig_rfc3971.c
+--- sendd-0.2/sendd/sig_rfc3971.c      2008-04-18 16:21:46.000000000 +0200
++++ sendd-0.2.new/sendd/sig_rfc3971.c  2008-09-10 11:14:35.000000000 +0200
+@@ -147,7 +147,7 @@
+       EVP_MD_CTX ctx[1];
+       EVP_PKEY *pub;
+       int rv = -1;
+-      int i, real_slen, min_bits;
++      int i, real_slen, min_bits, max_bits;
+       DEFINE_TIMESTAMP_VARS();
+       DBG_HEXDUMP(&dbg_cryptox, "key: ", key, klen);
+@@ -164,6 +164,12 @@
+                   "minimum: %d)", EVP_PKEY_bits(pub), min_bits);
+               return (-1);
+       }
++      max_bits = snd_conf_get_int(snd_max_key_bits);
++      if (EVP_PKEY_bits(pub) > max_bits) {
++              DBG(&dbg_snd, "Peer key too strong: %d bits (configured "
++                  "maximum: %d)", EVP_PKEY_bits(pub), max_bits);
++              return (-1);
++      }
+       real_slen = EVP_PKEY_size(pub);
+       if (real_slen < slen) {
+Index: sendd-0.2/sendd/snd_config.h
+===================================================================
+diff -urN sendd-0.2/sendd/snd_config.h sendd-0.2.new/sendd/snd_config.h
+--- sendd-0.2/sendd/snd_config.h       2008-04-18 16:21:46.000000000 +0200
++++ sendd-0.2.new/sendd/snd_config.h   2008-09-09 15:09:45.000000000 +0200
+@@ -42,6 +42,7 @@
+       snd_cga_params,
+       snd_full_secure,
+       snd_min_key_bits,
++      snd_max_key_bits,
+       snd_nonce_cache_gc_intvl,
+       snd_pfx_cache_gc_intvl,
+       snd_pkixip_conf,
diff --git a/ipv6/send/patches/003-keysig_8bytes_alignment.patch b/ipv6/send/patches/003-keysig_8bytes_alignment.patch
new file mode 100644 (file)
index 0000000..3ebc1a8
--- /dev/null
@@ -0,0 +1,22 @@
+This patch aligns the structure describing the RSA signature
+option to 8 bytes. Before that, send was padding with N bytes
+(4 on 32-bits architectures) using a cast in sendd/proto_sig.c :
+
+       so = (struct snd_opt_sig *)(nd_so);
+
+which would align to the number of bytes representing a pointer
+on your architecture.
+
+Index: sendd-0.2/sendd/snd_proto.h
+============================================================
+--- sendd-0.2/sendd/snd_proto.h        2008-04-18 16:21:46.000000000 +0200
++++ sendd-0.2.new/sendd/snd_proto.h    2008-10-05 16:08:34.000000000 +0200
+@@ -69,7 +69,7 @@
+       uint32_t                reserved;       /* opt hdr + reserved */
+       uint8_t                 keyhash[SND_KEYHASH_LEN];
+       uint8_t                 sig[0];
+-};
++} __attribute__((aligned(8)));
+ struct snd_opt_timestamp {
+       uint8_t                 type;
diff --git a/ipv6/send/patches/004-always_link_with_ncurses.patch b/ipv6/send/patches/004-always_link_with_ncurses.patch
new file mode 100644 (file)
index 0000000..0bb9c68
--- /dev/null
@@ -0,0 +1,31 @@
+We should always link with libncurses. This is not noticeable
+when building the debian packages because we install libncurses5
+runtime library as a dependency.
+
+Index: sendd-0.2/cgatool/Makefile
+===================================================================
+--- sendd-0.2/cgatool/Makefile 2008-10-05 16:26:28.000000000 +0200
++++ sendd-0.2.new/cgatool/Makefile     2008-10-21 18:03:28.000000000 +0200
+@@ -17,7 +17,7 @@
+ LDFLAGS= -L../libs/.libs
+ endif
+-LDLIBS += -lcrypto
++LDLIBS += -lcrypto -lncurses
+ ifeq ($(USE_THREADS),y)
+ LDLIBS += -lpthread
+Index: sendd-0.2/sendd/Makefile
+===================================================================
+diff -urN sendd-0.2/sendd/Makefile sendd-0.2.new/sendd/Makefile
+--- sendd-0.2/sendd/Makefile    2008-05-27 17:04:08.000000000 +0200
++++ sendd-0.2.new/sendd/Makefile        2008-10-21 18:49:05.000000000 +0200
+@@ -28,7 +28,7 @@
+ LDFLAGS= -L../libs/.libs
+ endif
+
+-LDLIBS += -lcrypto
++LDLIBS += -lcrypto -lncurses
+ LDLIBS += $(OSLIBS)
+
+ ifeq ($(USE_THREADS),y)