Binding sockets to devices in FreeBSD

Naveen Kumar g_naveen_k at yahoo.com
Thu Feb 19 16:06:10 PST 2004


Well it doesn't look like it would work for IPV4. 
If you look at the following code there is no place to
specify the interface index at packet level in send as
in IPV6. If the broadcast addresses on the different
interfaces were different then there is no problem the
sendto would work but if broadcast addresses are the
same then it wouldn't

int
rip_send_packet (caddr_t buf, int size, struct
sockaddr_in *to, 
		 struct interface *ifp, struct connected *connected)
{
  int ret, send_sock;
  struct sockaddr_in sin;

  if (IS_RIP_DEBUG_PACKET)
    {
      char dst[20];
      if (to)
        {
          strcpy(dst, inet_ntoa(to->sin_addr));
        }
      else
        {
          sin.sin_addr.s_addr = htonl
(INADDR_RIP_GROUP);
          strcpy(dst, inet_ntoa(sin.sin_addr));
        }
      zlog_info("rip_send_packet %s > %s (%s)",
               
inet_ntoa(connected->address->u.prefix4), dst,
ifp->name);
    }
  if (connected->flags & ZEBRA_IFA_SECONDARY)
    {
      /*
       * ZEBRA_IFA_SECONDARY is set on linux when an
interface is configured
       * with multiple addresses on the same subnet:
the first address
       * on the subnet is configured "primary", and
all subsequent addresses
       * on that subnet are treated as "secondary"
addresses. 
       * In order to avoid routing-table bloat on
other rip listeners, 
       * we do not send out RIP packets with
ZEBRA_IFA_SECONDARY source addrs.
       * XXX Since Linux is the only system for which
the ZEBRA_IFA_SECONDARY
       * flag is set, we would end up sending a packet
for a "secondary"
       * source address on non-linux systems.  
       */
      if (IS_RIP_DEBUG_PACKET)
        zlog_info("duplicate dropped");
      return 0;
    }

  /* Make destination address. */
  memset (&sin, 0, sizeof (struct sockaddr_in));
  sin.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
  sin.sin_len = sizeof (struct sockaddr_in);
#endif /* HAVE_SIN_LEN */

  /* When destination is specified, use it's port and
address. */
  if (to)
    {
      sin.sin_port = to->sin_port;
      sin.sin_addr = to->sin_addr;
      send_sock = rip->sock;
    }
  else
    {

      sin.sin_port = htons (RIP_PORT_DEFAULT);
      sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);

      /*
       * 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 for each packet. 
       */
      send_sock = socket(AF_INET, SOCK_DGRAM, 0);
      if (send_sock < 0)
        {
          zlog_warn("rip_send_packet 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,
connected, if_is_pointopoint(ifp));
    }

  ret = sendto (send_sock, buf, size, 0, (struct
sockaddr *)&sin,
		sizeof (struct sockaddr_in));

--- Vincent Jardin <vjardin at free.fr> wrote:
> Hi,
> 
> You need to use sendto or sendmsg.
> 
> For example, with IPv6, Quagga is sending IPv6
> multicast packet on a per 
> interface basis. The interface's ifindex is provided
> into the pktinfo 
> structure.
> 
> int
> ripng_send_packet (caddr_t buf, int bufsize, struct
> sockaddr_in6 *to,
>                    struct interface *ifp)
> {
>   int ret;
>   struct msghdr msg;
>   struct iovec iov;
>   struct cmsghdr  *cmsgptr;
>   char adata [256];
>   struct in6_pktinfo *pkt;
>   struct sockaddr_in6 addr;
> 
>   [...]
> 
>   memset (&addr, 0, sizeof (struct sockaddr_in6));
>   addr.sin6_family = AF_INET6;
> #ifdef SIN6_LEN
>   addr.sin6_len = sizeof (struct sockaddr_in6);
> #endif /* SIN6_LEN */
>   addr.sin6_flowinfo = htonl
> (RIPNG_PRIORITY_DEFAULT);
> 
>  [...]
>       inet_pton(AF_INET6, RIPNG_GROUP,
> &addr.sin6_addr);
>       addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
>  [...]
> 
>   msg.msg_name = (void *) &addr;
>   msg.msg_namelen = sizeof (struct sockaddr_in6);
>   msg.msg_iov = &iov;
>   msg.msg_iovlen = 1;
>   msg.msg_control = (void *) adata;
>   msg.msg_controllen = CMSG_SPACE(sizeof(struct
> in6_pktinfo));
> 
>   iov.iov_base = buf;
>   iov.iov_len = bufsize;
> 
>   cmsgptr = (struct cmsghdr *)adata;
>   cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct
> in6_pktinfo));
>   cmsgptr->cmsg_level = IPPROTO_IPV6;
>   cmsgptr->cmsg_type = IPV6_PKTINFO;
> 
>   pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
>   memset (&pkt->ipi6_addr, 0, sizeof (struct
> in6_addr));
>   pkt->ipi6_ifindex = ifp->ifindex;
> 
>   ret = sendmsg (ripng->sock, &msg, 0);
> 
> [...]
> 
>   return ret;
> }
> 
> About IPv4, see the sendto() use case of
> ripd/ripd.c.
> 
> Moreover these solutions, which are used by Quagga,
> are portable on most of 
> the OSes (Linux, FreeBSD, OpenBSD, NetBSD, Solaris,
> ...).
> 
> Regards,
>   Vincent
> 
> 
> On Thursday 19 February 2004 10:54, Andreas T wrote:
> > Hi all,
> >
> > I am developing an implementation of the Optimized
> LinkState Routing
> > protocol(RFC3626) for Linux(www.olsr.org). OLSR is
> a routing protocol
> > for mobile, multihop, wireless ad-hoc networks.
> >
> > I would really like to have my code compile on
> FreeBSD - but there is
> > one major issue.
> >
> > OLSR sends control traffic broadcasted(IPv4) or
> multicasted(IPv6) on a
> > pr.interface basis. That means that a node running
> OLSR on two
> > interfaces a and b, would not always broadcast the
> same content in
> > messages sent on a and b. This works fine using
> IPv4 and broadcast as
> > long as the interfaces uses different broadcast
> addresses - but as soon
> > as two interfaces is set up with the same
> broadcastaddress(or as soon as
> > one uses IPv6 with the same multicastgroup) any
> message (sent on the
> > broadcastsocket) will be transmitted on both
> interfaces.
> > I hope this made some sense :)
> >
> > Bottom line is that one has to be able to control
> on which interface
> > packets are sent. To do this in Linux i use the
> SO_BINDTODEVICE
> > flag(with setsockopt(2)). That way I can have one
> socket for each
> > interface OLSR is to use regradless of
> destinationaddress.
> >
> > In FreeBSD there is no SO_BINDTODEVICE or
> equalivant as far as I can
> > see. To me it seems like BPF could provide the
> functioning I need. Is
> > this so? Can BPF in some way help me control on
> which interface packets
> > are transmitted?
> > If so I would really appreciate some (pseudo or
> real)code examples to
> > get me started or some links to such material - as
> I am totally new to
> > the BPF interface(and the concept).
> >
> > If BPF is not the way to go I would appreciate any
> help in finding a way
> > of doing this in FreeBSD.
> >
> > I could ofcause try to figure this out by myself -
> but as FreeBSD
> > porting is not too high prioritized for now I
> figured I'd rather be lazy
> > and ask you experts :)
> >
> >
> > Thanks!
> >
> > regards,
> > Andreas T
> _______________________________________________
> freebsd-net at freebsd.org mailing list
>
http://lists.freebsd.org/mailman/listinfo/freebsd-net
> To unsubscribe, send any mail to
"freebsd-net-unsubscribe at freebsd.org"



__________________________________
Do you Yahoo!?
Yahoo! Mail SpamGuard - Read only the mail you want.
http://antispam.yahoo.com/tools


More information about the freebsd-net mailing list