Jan 8, 2004, 2:20 PM
Post #4 of 80
(5558 views)
Permalink
> From sowmini@quasimodo.East.Sun.COM Thu Dec 25 20:40:27 2003
>
> >
> > There is one bug left, but I hope Sowmini will fix it soon (see
> > [quagga-dev 490] Re: Problems with ripd in quagga-0.96.4).
> >
>
found out what the problem was. I was always closing send_sock,
whereas I should only have closed it for (!to). Here's the new patch
which worked for me on linux with ripv1. Can you please try and
confirm that this one works, so that Paul can commit it?
--Sowmini
===================================================================
RCS file: ripd/rip_interface.c,v
retrieving revision 1.13
diff -uwb -r1.13 ripd/rip_interface.c
--- ripd/rip_interface.c 2003/10/15 23:20:17 1.13
+++ ripd/rip_interface.c 2003/11/07 16:07:38
@@ -146,13 +146,18 @@
struct in_addr addr;
struct prefix_ipv4 *p;
+ if (connected != NULL)
+ {
if (if_pointopoint)
p = (struct prefix_ipv4 *) connected->destination;
else
p = (struct prefix_ipv4 *) connected->address;
-
addr = p->prefix;
-
+ }
+ else
+ {
+ addr.s_addr = INADDR_ANY;
+ }
if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
addr, 0, 0) < 0)
@@ -173,7 +178,10 @@
/* Address shoud be any address. */
from.sin_family = AF_INET;
+ if (connected)
addr = ((struct prefix_ipv4 *) connected->address)->prefix;
+ else
+ addr.s_addr = INADDR_ANY;
from.sin_addr = addr;
#ifdef HAVE_SIN_LEN
from.sin_len = sizeof (struct sockaddr_in);
@@ -182,7 +190,6 @@
if (ripd_privs.change (ZPRIVS_RAISE))
zlog_err ("rip_interface_multicast_set: could not raise privs");
- bind (sock, NULL, 0); /* unbind any previous association */
ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in));
if (ret < 0)
{
===================================================================
RCS file: ripd/ripd.c,v
retrieving revision 1.11
diff -uwb -r1.11 ripd/ripd.c
--- ripd/ripd.c 2003/10/15 23:20:17 1.11
+++ ripd/ripd.c 2004/01/08 15:46:45
@@ -42,6 +42,11 @@
#include "ripd/ripd.h"
#include "ripd/rip_debug.h"
+/*
+ * The source address to be used when sending the packet
+ */
+struct connected *source_address;
+
extern struct zebra_privs_t ripd_privs;
/* RIP Structure. */
@@ -1237,7 +1242,7 @@
rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to,
struct interface *ifp)
{
- int ret;
+ int ret, send_sock;
struct sockaddr_in sin;
/* Make destination address. */
@@ -1252,6 +1257,7 @@
{
sin.sin_port = to->sin_port;
sin.sin_addr = to->sin_addr;
+ send_sock = rip->sock;
}
else
{
@@ -1259,11 +1265,32 @@
sin.sin_port = htons (RIP_PORT_DEFAULT);
sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
- /* caller has set multicast interface */
+ /*
+ * we have to open a new socket for each packet because
+ * this is the most portable way to bind to a different
+ * source ipv4 address.
+ */
+ send_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (send_sock < 0)
+ {
+ zlog_warn("could not create socket %s", strerror(errno));
+ return -1;
+ }
+
+ sockopt_broadcast (send_sock);
+ sockopt_reuseaddr (send_sock);
+ sockopt_reuseport (send_sock);
+#ifdef RIP_RECVMSG
+ setsockopt_pktinfo (send_sock);
+#endif /* RIP_RECVMSG */
+ rip_interface_multicast_set(send_sock, source_address,
+ if_is_pointopoint(ifp));
+ /* reset source address */
+ source_address = NULL;
}
- ret = sendto (rip->sock, buf, size, 0, (struct sockaddr *)&sin,
+ ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin,
sizeof (struct sockaddr_in));
if (IS_RIP_DEBUG_EVENT)
@@ -1273,6 +1300,8 @@
if (ret < 0)
zlog_warn ("can't send packet : %s", strerror (errno));
+ if (!to)
+ close(send_sock);
return ret;
}
@@ -1839,7 +1868,7 @@
return len;
}
-/* Make socket for RIP protocol. */
+/* Make socket for RIP protocol and bind it to the inaddr. */
int
rip_create_socket ()
{
@@ -1848,7 +1877,6 @@
struct sockaddr_in addr;
struct servent *sp;
- memset (&addr, 0, sizeof (struct sockaddr_in));
/* Set RIP port. */
sp = getservbyname ("router", "udp");
@@ -2358,8 +2386,7 @@
if (ifaddr->family != AF_INET)
continue;
- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
+ source_address = connected;
if (vsend & RIPv1)
rip_update_interface (ifp, RIPv1, route_type, ifaddr);
if (vsend & RIPv2)
@@ -2588,8 +2615,7 @@
if (p->family != AF_INET)
continue;
- rip_interface_multicast_set(rip->sock, connected,
- if_is_pointopoint(ifp));
+ source_address = connected;
if (rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet),
to, ifp) != sizeof (rip_packet))
return -1;