pflow(4) without flowsrc

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

pflow(4) without flowsrc

Nathanael Rensen-2
If no flowsrc is specified on a pflow(4) interface then the src address
is determined by ip_output(). However prior to calling ip_output() pflow(4)
has already calculated the UPD pseudo-header checksum based on INADDR_ANY.
This results in a bad UPD checksum and the resulting pflow packet is
rejected by the receiver.

The diff below resolves this by calling in_selectsrc() if flowsrc is not
specified.

Nathanael

Index: if_pflow.c
===================================================================
RCS file: /cvs/src/sys/net/if_pflow.c,v
retrieving revision 1.34
diff -u -p -r1.34 if_pflow.c
--- if_pflow.c 13 Aug 2013 08:44:05 -0000 1.34
+++ if_pflow.c 30 Aug 2013 18:54:03 -0000
@@ -1512,8 +1512,37 @@ pflow_sendout_mbuf(struct pflow_softc *s
  struct ifnet *ifp = &sc->sc_if;
 #endif
  struct ip *ip;
+ struct in_addr sender_ip;
  int err;
 
+ /* Determine the sender address */
+ sender_ip = sc->sc_sender_ip;
+ if (sender_ip.s_addr == INADDR_ANY) {
+ struct sockaddr_in sin;
+ struct sockaddr_in *ifaddr;
+ struct route ro;
+
+ bzero(&ro, sizeof(ro));
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = sc->sc_receiver_port;
+ sin.sin_addr = sc->sc_receiver_ip;
+
+ err = 0;
+ ifaddr = in_selectsrc(&sin, &ro, 0, NULL, &err, 0);
+ if (ifaddr == NULL) {
+ if (err == 0)
+ err = EADDRNOTAVAIL;
+ return err;
+ }
+
+ sender_ip = ifaddr->sin_addr;
+
+ if (ro.ro_rt)
+ rtfree(ro.ro_rt);
+ }
+
  /* UDP Header*/
  M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
  if (m == NULL) {
@@ -1523,7 +1552,7 @@ pflow_sendout_mbuf(struct pflow_softc *s
 
  ui = mtod(m, struct udpiphdr *);
  ui->ui_pr = IPPROTO_UDP;
- ui->ui_src = sc->sc_sender_ip;
+ ui->ui_src = sender_ip;
  ui->ui_sport = sc->sc_sender_port;
  ui->ui_dst = sc->sc_receiver_ip;
  ui->ui_dport = sc->sc_receiver_port;

Reply | Threaded
Open this post in threaded view
|

Re: pflow(4) without flowsrc

Martin Pieuchot-2
On 31/08/13(Sat) 04:28, Nathanael Rensen wrote:
> If no flowsrc is specified on a pflow(4) interface then the src address
> is determined by ip_output(). However prior to calling ip_output() pflow(4)
> has already calculated the UPD pseudo-header checksum based on INADDR_ANY.
> This results in a bad UPD checksum and the resulting pflow packet is
> rejected by the receiver.
>
> The diff below resolves this by calling in_selectsrc() if flowsrc is not
> specified.

I'm not sure we want to add yet-another different chunk of code to
determine a source address, especially when I'm working on reducing
their number ;)

I'm not familiar with pflow(4), but is there any advantage of not
specifying a flowsrc target?  Because reducing the number of code
path passing an INADDR_ANY source address would simplify a lot of
our address lookups.

Otherwise did you considered deferring the checksum?

> Index: if_pflow.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pflow.c,v
> retrieving revision 1.34
> diff -u -p -r1.34 if_pflow.c
> --- if_pflow.c 13 Aug 2013 08:44:05 -0000 1.34
> +++ if_pflow.c 30 Aug 2013 18:54:03 -0000
> @@ -1512,8 +1512,37 @@ pflow_sendout_mbuf(struct pflow_softc *s
>   struct ifnet *ifp = &sc->sc_if;
>  #endif
>   struct ip *ip;
> + struct in_addr sender_ip;
>   int err;
>  
> + /* Determine the sender address */
> + sender_ip = sc->sc_sender_ip;
> + if (sender_ip.s_addr == INADDR_ANY) {
> + struct sockaddr_in sin;
> + struct sockaddr_in *ifaddr;
> + struct route ro;
> +
> + bzero(&ro, sizeof(ro));
> + bzero(&sin, sizeof(sin));
> + sin.sin_len = sizeof(sin);
> + sin.sin_family = AF_INET;
> + sin.sin_port = sc->sc_receiver_port;
> + sin.sin_addr = sc->sc_receiver_ip;
> +
> + err = 0;
> + ifaddr = in_selectsrc(&sin, &ro, 0, NULL, &err, 0);
> + if (ifaddr == NULL) {
> + if (err == 0)
> + err = EADDRNOTAVAIL;
> + return err;
> + }
> +
> + sender_ip = ifaddr->sin_addr;
> +
> + if (ro.ro_rt)
> + rtfree(ro.ro_rt);
> + }
> +
>   /* UDP Header*/
>   M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
>   if (m == NULL) {
> @@ -1523,7 +1552,7 @@ pflow_sendout_mbuf(struct pflow_softc *s
>  
>   ui = mtod(m, struct udpiphdr *);
>   ui->ui_pr = IPPROTO_UDP;
> - ui->ui_src = sc->sc_sender_ip;
> + ui->ui_src = sender_ip;
>   ui->ui_sport = sc->sc_sender_port;
>   ui->ui_dst = sc->sc_receiver_ip;
>   ui->ui_dport = sc->sc_receiver_port;
>

Reply | Threaded
Open this post in threaded view
|

Re: pflow(4) without flowsrc

Florian Obser-2
On Mon, Sep 02, 2013 at 11:11:43AM +0200, Martin Pieuchot wrote:

> On 31/08/13(Sat) 04:28, Nathanael Rensen wrote:
> > If no flowsrc is specified on a pflow(4) interface then the src address
> > is determined by ip_output(). However prior to calling ip_output() pflow(4)
> > has already calculated the UPD pseudo-header checksum based on INADDR_ANY.
> > This results in a bad UPD checksum and the resulting pflow packet is
> > rejected by the receiver.
> >
> > The diff below resolves this by calling in_selectsrc() if flowsrc is not
> > specified.
>
> I'm not sure we want to add yet-another different chunk of code to
> determine a source address, especially when I'm working on reducing
> their number ;)
>
> I'm not familiar with pflow(4), but is there any advantage of not
> specifying a flowsrc target?  Because reducing the number of code
> path passing an INADDR_ANY source address would simplify a lot of
> our address lookups.

If there is no strong usecase for not specifying flowsrc I think it's
better to not take the interface up if there is no flowsrc like we are
doing with flowdst. That requires some dicking around in pflowioctl()
and needs to be documented. (And don't take it up if someone sets it
explicitly to INADDR_ANY.)

Also style(9) says:
     Don't put declarations inside
     blocks unless the routine is unusually complicated.

>
> Otherwise did you considered deferring the checksum?
>
> > Index: if_pflow.c
> > ===================================================================
> > RCS file: /cvs/src/sys/net/if_pflow.c,v
> > retrieving revision 1.34
> > diff -u -p -r1.34 if_pflow.c
> > --- if_pflow.c 13 Aug 2013 08:44:05 -0000 1.34
> > +++ if_pflow.c 30 Aug 2013 18:54:03 -0000
> > @@ -1512,8 +1512,37 @@ pflow_sendout_mbuf(struct pflow_softc *s
> >   struct ifnet *ifp = &sc->sc_if;
> >  #endif
> >   struct ip *ip;
> > + struct in_addr sender_ip;
> >   int err;
> >  
> > + /* Determine the sender address */
> > + sender_ip = sc->sc_sender_ip;
> > + if (sender_ip.s_addr == INADDR_ANY) {
> > + struct sockaddr_in sin;
> > + struct sockaddr_in *ifaddr;
> > + struct route ro;
> > +
> > + bzero(&ro, sizeof(ro));
> > + bzero(&sin, sizeof(sin));
> > + sin.sin_len = sizeof(sin);
> > + sin.sin_family = AF_INET;
> > + sin.sin_port = sc->sc_receiver_port;
> > + sin.sin_addr = sc->sc_receiver_ip;
> > +
> > + err = 0;
> > + ifaddr = in_selectsrc(&sin, &ro, 0, NULL, &err, 0);
> > + if (ifaddr == NULL) {
> > + if (err == 0)
> > + err = EADDRNOTAVAIL;
> > + return err;
> > + }
> > +
> > + sender_ip = ifaddr->sin_addr;
> > +
> > + if (ro.ro_rt)
> > + rtfree(ro.ro_rt);
> > + }
> > +
> >   /* UDP Header*/
> >   M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
> >   if (m == NULL) {
> > @@ -1523,7 +1552,7 @@ pflow_sendout_mbuf(struct pflow_softc *s
> >  
> >   ui = mtod(m, struct udpiphdr *);
> >   ui->ui_pr = IPPROTO_UDP;
> > - ui->ui_src = sc->sc_sender_ip;
> > + ui->ui_src = sender_ip;
> >   ui->ui_sport = sc->sc_sender_port;
> >   ui->ui_dst = sc->sc_receiver_ip;
> >   ui->ui_dport = sc->sc_receiver_port;
> >
>

--
I'm not entirely sure you are real.