コード例 #1
0
/* Simulate the effect of a lossy link on a received packet */
static inline int simulate_link(char *buf, int len)
{
	/* Do we drop it? */
	if (loss_rate && RAND_PERCENT < loss_rate) {
		LOG_PKT(buf, "Dropping packet");
		return EXIT_SUCCESS;
	}
	/* Do we cut it after the header? */
	if (cut_rate && RAND_PERCENT < cut_rate) {
		LOG_PKT(buf, "Cutting packet");
		len = 4;
	/* or do we corrupt it? */
	} else if (err_rate && RAND_PERCENT < err_rate) {
		LOG_PKT(buf, "Corrupting packet");
		buf[len - 1] = ~buf[len - 1]; /* invert last byte of the CRC */
	}
	/* Do we want to simulate delay? */
	if (delay) {
		/* Random delay to add is capped to 10s */
		unsigned int applied_delay = RAND_PERCENT > 49 ?
			delay + rand() % jitter :
			delay - rand() % jitter;
		applied_delay %= 10000;
		LOG_PKT_FMT(buf, "Delayed packet by %u ms\n", applied_delay);
		/* Create a slot for the packet queue */
		struct pkt_slot *slot;
		if (!(slot = malloc(sizeof(*slot)))) {
			fprintf(stderr,
					"Failed to allocate memory for a delayed packet!\n");
			return EXIT_FAILURE;
		}
		/* Copy the packet in the slot */
		memcpy(slot->buf, buf, len);
		slot->size = len;
		/* Register expiration date: current date + delay */
		slot->ts.tv_sec = last_clock.tv_sec + applied_delay / 1000;
		/* delay is in ms not us! */
		slot->ts.tv_usec = last_clock.tv_usec + (applied_delay % 1000) * 1000;
		/* Enqueue the new slot */
		if (minq_push(pkt_queue, slot)) {
			perror("Failed to enqueue a packet!");
			return EXIT_FAILURE;
		}
	} else {
		/* Forward it to the host we're proxying */
		if (write_out(buf, len)) {
			perror("Failed to write all bytes");
			return EXIT_FAILURE;
		}
	}
	return EXIT_SUCCESS;
}
コード例 #2
0
/* Send a packet to the host we're proxying */
static int write_out(const char *buf, int len)
{
	LOG_PKT(buf, "Sent packet");
	return sendto(sfd, buf, len, 0,
				(struct sockaddr*)&dest_addr, sizeof(dest_addr)) == len ?
		EXIT_SUCCESS : EXIT_FAILURE;
}
コード例 #3
0
ファイル: dbdes.c プロジェクト: ColinBS/bird
void
ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
		   struct ospf_neighbor *n)
{
  struct ospf_proto *p = ifa->oa->po;
  const char *err_dsc = NULL;
  u32 rcv_ddseq, rcv_options;
  u16 rcv_iface_mtu;
  u8 rcv_imms;
  uint plen, err_val = 0;

  /* RFC 2328 10.6 */

  plen = ntohs(pkt->length);
  if (plen < ospf_dbdes_hdrlen(p))
  {
    LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
    return;
  }

  OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);

  ospf_neigh_sm(n, INM_HELLOREC);

  if (ospf_is_v2(p))
  {
    struct ospf_dbdes2_packet *ps = (void *) pkt;
    rcv_iface_mtu = ntohs(ps->iface_mtu);
    rcv_options = ps->options;
    rcv_imms = ps->imms;
    rcv_ddseq = ntohl(ps->ddseq);
  }
  else /* OSPFv3 */
  {
    struct ospf_dbdes3_packet *ps = (void *) pkt;
    rcv_options = ntohl(ps->options);
    rcv_iface_mtu = ntohs(ps->iface_mtu);
    rcv_imms = ps->imms;
    rcv_ddseq = ntohl(ps->ddseq);
  }

  switch (n->state)
  {
  case NEIGHBOR_DOWN:
  case NEIGHBOR_ATTEMPT:
  case NEIGHBOR_2WAY:
    OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
    return;

  case NEIGHBOR_INIT:
    ospf_neigh_sm(n, INM_2WAYREC);
    if (n->state != NEIGHBOR_EXSTART)
      return;

  case NEIGHBOR_EXSTART:
    if ((ifa->type != OSPF_IT_VLINK) &&
	(rcv_iface_mtu != ifa->iface->mtu) &&
	(rcv_iface_mtu != 0) &&
	(ifa->iface->mtu != 0))
      LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
		   n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);

    if ((rcv_imms == DBDES_IMMS) &&
	(n->rid > p->router_id) &&
	(plen == ospf_dbdes_hdrlen(p)))
    {
      /* I'm slave! */
      n->dds = rcv_ddseq;
      n->ddr = rcv_ddseq;
      n->options = rcv_options;
      n->myimms &= ~DBDES_MS;
      n->imms = rcv_imms;
      tm_stop(n->dbdes_timer);
      ospf_neigh_sm(n, INM_NEGDONE);
      ospf_send_dbdes(p, n);
      break;
    }

    if (!(rcv_imms & DBDES_I) &&
	!(rcv_imms & DBDES_MS) &&
	(n->rid < p->router_id) &&
	(n->dds == rcv_ddseq))
    {
      /* I'm master! */
      n->options = rcv_options;
      n->ddr = rcv_ddseq - 1;	/* It will be set corectly a few lines down */
      n->imms = rcv_imms;
      ospf_neigh_sm(n, INM_NEGDONE);
      /* Continue to the NEIGHBOR_EXCHANGE case */
    }
    else
    {
      DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
      break;
    }

  case NEIGHBOR_EXCHANGE:
    if ((rcv_imms == n->imms) &&
	(rcv_options == n->options) &&
	(rcv_ddseq == n->ddr))
      goto duplicate;

    if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
      DROP("MS-bit mismatch", rcv_imms);

    if (rcv_imms & DBDES_I)
      DROP("I-bit mismatch", rcv_imms);

    if (rcv_options != n->options)
      DROP("options mismatch", rcv_options);

    n->ddr = rcv_ddseq;
    n->imms = rcv_imms;

    if (n->myimms & DBDES_MS)
    {
      /* MASTER */

      if (rcv_ddseq != n->dds)
	DROP("DD sequence number mismatch", rcv_ddseq);

      n->dds++;

      if (ospf_process_dbdes(p, pkt, n) < 0)
	return;

      if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
      {
	tm_stop(n->dbdes_timer);
	ospf_neigh_sm(n, INM_EXDONE);
	break;
      }

      ospf_send_dbdes(p, n);
      tm_start(n->dbdes_timer, n->ifa->rxmtint);
    }
    else
    {
      /* SLAVE */

      if (rcv_ddseq != (n->dds + 1))
	DROP("DD sequence number mismatch", rcv_ddseq);

      n->ddr = rcv_ddseq;
      n->dds = rcv_ddseq;

      if (ospf_process_dbdes(p, pkt, n) < 0)
	return;

      ospf_send_dbdes(p, n);

      if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
	ospf_neigh_sm(n, INM_EXDONE);
    }
    break;

  case NEIGHBOR_LOADING:
  case NEIGHBOR_FULL:
    if ((rcv_imms == n->imms) &&
	(rcv_options == n->options) &&
	(rcv_ddseq == n->ddr))
      goto duplicate;

    DROP("too late for DD exchange", n->state);

  default:
    bug("Undefined interface state");
  }
  return;

duplicate:
  OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");

  /* Slave should retransmit DBDES packet */
  if (!(n->myimms & DBDES_MS))
    ospf_rxmt_dbdes(p, n);
  return;

drop:
  LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
	  n->rid, ifa->ifname, err_dsc, err_val);

  ospf_neigh_sm(n, INM_SEQMIS);
  return;
}
コード例 #4
0
ファイル: serval_ipv4.c プロジェクト: basukaladagi/serval
int serval_ipv4_xmit(struct sk_buff *skb)
{
        struct sock *sk = skb->sk;
        int err = 0;
#if defined(OS_LINUX_KERNEL)

	/*
          This is pretty much a copy paste from ip_queue_xmit
          (ip_output.c), but which modifications that take into
          account Serval specific stuff.
          
          It will route the packet according to the IP stack's routing
          table and output for standard IP output processing.
         */
        struct iphdr *iph;
        struct rtable *rt;
        struct inet_sock *inet = inet_sk(sk);
	struct ip_options *opt = NULL; /*inet->inet_opt; */
        int ifindex;

	/*
	   The SAL has dirtied the control block that IP expects to be
	zeroed out. 
	We need to make sure it is initialized again. Otherwise, there
	might be stack corruptions when IP functions try to read the
	IPCB. (This happens in, e.g., icmp_send when reading ip options.)  
	*/
        memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
        
	/* 
         * Skip all of this if the packet is already routed,
         */
        rcu_read_lock();

        rt = skb_rtable(skb);

        if (rt != NULL) {
                LOG_PKT("Packet already routed\n");
                goto packet_routed;
        }
        /* Make sure we can route this packet. */
        rt = (struct rtable *)__sk_dst_check(sk, 0);

        if (skb->dev) {
                ifindex = skb->dev->ifindex;
        } else {
                ifindex = sk->sk_bound_dev_if;
        }

        if (rt == NULL) {
                struct flowi fl;

                serval_flow_init_output(&fl, ifindex, 
                                        sk->sk_mark, 
                                        RT_CONN_FLAGS(sk), 0,
                                        skb->protocol,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
                                        inet_sk_flowi_flags(sk),
#else
                                        0,
#endif
                                        inet->inet_daddr,
                                        inet->inet_saddr,
                                        0, 0);
                
                serval_security_sk_classify_flow(sk, &fl);
                
                rt = serval_ip_route_output_flow(sock_net(sk), &fl, sk, 0);

                if (!rt) {
                        LOG_DBG("No route!\n");
                        err = -EHOSTUNREACH;
                        rcu_read_unlock();
                        goto drop;
                }

                /* Setup the socket to use this route in the future */
                sk_setup_caps(sk, route_dst(rt));

        } else {
                LOG_PKT("Using route already associated with socket\n");
        }
        
#if defined(ENABLE_DEBUG)
        {
                char src[18], dst[18];
                LOG_PKT("Route found %s -> %s %s\n",
                        inet_ntop(AF_INET, &rt->rt_src, 
                                  src, sizeof(src)),
                        inet_ntop(AF_INET, &rt->rt_dst, 
                                  dst, sizeof(dst)),
                        route_dst(rt)->dev ? 
                        route_dst(rt)->dev->name : "(null)");
        }
#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35))
        skb_dst_set(skb, dst_clone(route_dst(rt)));
#else
        skb_dst_set_noref(skb, route_dst(rt));
#endif
 packet_routed:
        if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {
                err = -EHOSTUNREACH;
                rcu_read_unlock();
                LOG_DBG("dest is not gateway!\n");
                goto drop;
        }


	/* OK, we know where to send it, allocate and build IP header. */
	skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
	skb_reset_network_header(skb);
	iph = ip_hdr(skb);
	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
	if (ip_dont_fragment(sk, route_dst(rt)) && !skb->local_df)
		iph->frag_off = htons(IP_DF);
	else
		iph->frag_off = 0;
	iph->ttl      = ip_select_ttl(inet, route_dst(rt));
	iph->protocol = skb->protocol;
	iph->saddr    = rt->rt_src;
	iph->daddr    = rt->rt_dst;

	if (opt && opt->optlen) {
                LOG_WARN("IP options not implemented\n");
                /* For some reason, enabling the code below gives the
                 * error: "Unknown symbol ip_options_build (err 0)"
                 * when loading the serval.ko module. Seems the
                 * ip_options_build function is not exported.
                 */
                /*
		iph->ihl += opt->optlen >> 2;
		ip_options_build(skb, opt, inet->inet_daddr, rt, 0);
                */
	}
        
        ip_select_ident_more(iph, route_dst(rt), sk,
			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);

	skb->priority = sk->sk_priority;

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
	skb->mark = sk->sk_mark;
#endif
	err = serval_ip_local_out(skb);

	rcu_read_unlock();
#else
        /*
          FIXME: We should not rely on an outgoing interface here.
          Instead, we should route the packet like we do in the
          kernel. But, we currently do not have an IP routing table
          for userlevel.
         */

        if (!skb->dev)
                skb->dev = __dev_get_by_index(sock_net(sk),
                                              sk->sk_bound_dev_if);

        if (!skb->dev) {
                LOG_ERR("no output device set in skb!\n");
                err = -ENODEV;
                goto drop;
        }
        err = serval_ipv4_fill_in_hdr(sk, skb, inet_sk(sk)->inet_saddr,
                                      inet_sk(sk)->inet_daddr);
        
        if (err < 0) {
                LOG_ERR("hdr failed\n");
                goto drop;
        }

        /* Transmit */
        err = serval_ip_local_out(skb);
#endif /* OS_LINUX_KERNEL */    
 out:
        if (err < 0) {
                LOG_ERR("xmit failed: %d\n", err);
        }

        return err;
drop:
        LOG_DBG("Dropping skb!\n");

        FREE_SKB(skb);
        
        goto out;
}