/* * Add an ip header to a skbuff and send it out. * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options_rcu *opt) { struct inet_sock *inet = inet_sk(sk); struct rtable *rt = skb_rtable(skb); struct iphdr *iph; /* Build the IP header. */ skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0)); skb_reset_network_header(skb); iph = ip_hdr(skb); iph->version = 4; iph->ihl = 5; iph->tos = inet->tos; if (ip_dont_fragment(sk, &rt->dst)) iph->frag_off = htons(IP_DF); else iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->dst); iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); iph->saddr = saddr; iph->protocol = sk->sk_protocol; ip_select_ident(skb, sk); if (opt && opt->opt.optlen) { iph->ihl += opt->opt.optlen>>2; ip_options_build(skb, &opt->opt, daddr, rt, 0); }
/* * Add an ip header to a skbuff and send it out. * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, u32 saddr, u32 daddr, struct ip_options *opt) { struct inet_sock *inet = inet_sk(sk); struct rtable *rt = (struct rtable *)skb->dst; struct iphdr *iph; /* Build the IP header. */ if (opt) iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen); else iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr)); iph->version = 4; iph->ihl = 5; iph->tos = inet->tos; if (ip_dont_fragment(sk, &rt->u.dst)) iph->frag_off = htons(IP_DF); else iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->u.dst); iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; iph->protocol = sk->sk_protocol; iph->tot_len = htons(skb->len); ip_select_ident(iph, &rt->u.dst, sk); skb->nh.iph = iph; if (opt && opt->optlen) { iph->ihl += opt->optlen>>2; ip_options_build(skb, opt, daddr, rt, 0); }
int ip_format_and_send_pkt(struct sk_buff *skb,struct sock*sk,__be32 saddr, __be32 daddr,u16 tcp_len) { int ret = 0; struct net *pnet = sock_net(sk); struct netns_ipv4 *n_ipv4 = &pnet->ipv4; struct inet_sock *inet = inet_sk(sk); struct tcphdr *th = tcp_hdr(skb); struct iphdr *iph = ip_hdr(skb); iph->tos = inet->tos; iph->tot_len = htons(sizeof(struct iphdr) + tcp_len); iph->frag_off = htons(IP_DF); ip_select_ident(skb, sk); iph->ttl = ip_select_ttl(sk); iph->protocol = sk->sk_protocol; iph->daddr = daddr; iph->saddr = saddr; iph->check = 0; th->check = 0; th->check = get_ipv4_psd_sum(iph); if(n_ipv4->aft_route_out){ ret = n_ipv4->aft_route_out(skb); if(ret < 0) return US_ENETUNREACH; } return mbuf_format_and_send(skb, tcp_len); }
int ip_queue_xmit(struct sk_buff *skb) { //smallboy: We delete all the route here; //smallboy: ROUTE ROUTE ROUTE ROUTE !!!!! struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); struct tcphdr *th = tcp_hdr(skb); struct net *pnet = sock_net(sk); struct netns_ipv4 *n_ipv4 = &pnet->ipv4; struct iphdr *iph; u32 ihl; s32 ret = 0; //ihl = sizeof(struct iphdr) + (inet_opt ? inet_opt->optlen : 0); ihl = sizeof(struct iphdr); skb_push(skb, ihl); skb_reset_network_header(skb); iph = ip_hdr(skb); iph->version = 4; //smallboy: Attention for ipv6; iph->ihl = ihl>>2; iph->tos = inet->tos; iph->tot_len = htons(skb->len); iph->frag_off = htons(IP_DF); iph->ttl = ip_select_ttl(sk); iph->protocol = sk->sk_protocol; iph->daddr = inet->inet_daddr; // iph->saddr = inet->inet_rcv_saddr; //smallboy:Attention here; ip_select_ident_more(iph, sk, (skb->gso_segs ?: 1) - 1); th->check = 0; //th->check = get_ipv4_udptcp_checksum(iph , th); iph->check = 0; th->check = get_ipv4_psd_sum(iph); //iph->check = ip_fast_csum(iph, iph->ihl); if(n_ipv4->aft_route_out){ ret = n_ipv4->aft_route_out(skb); if(ret < 0){ skb_reset_data_header(skb); return ret; } } ret = ip_local_out(skb); return ret; }
/* * Add an ip header to a skbuff and send it out. * */ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,__be32 saddr, __be32 daddr) { int ret = 0; struct inet_sock *inet = inet_sk(sk); struct tcphdr *th = tcp_hdr(skb); struct net *pnet = sock_net(sk); struct netns_ipv4 *n_ipv4 = &pnet->ipv4; struct iphdr *iph; // Build the IP header. skb_push(skb, sizeof(struct iphdr)); ////+ (opt ? opt->opt.optlen : 0) skb_reset_network_header(skb); iph = ip_hdr(skb); iph->version = 4; iph->ihl = 5; //iph->tos = 0;//inet->tos; iph->tos = inet->tos; iph->tot_len = htons(skb->len); iph->frag_off = htons(IP_DF); //smallboy :must before ip_select_ident; ip_select_ident(skb, sk); iph->ttl = ip_select_ttl(sk); iph->protocol = sk->sk_protocol; iph->daddr = daddr; iph->saddr = saddr; iph->check = 0; //iph->check = ip_fast_csum(iph, iph->ihl); th->check = 0; //th->check = get_ipv4_udptcp_checksum(iph , th); th->check = get_ipv4_psd_sum(iph); //skb->mark = sk->sk_mark; //fprintf(stderr,"TH:%u,src:%s,dst:%s,sport:%u,dport:%u,seq:%-12u,ack:%-12u,ipid:%-12u,len:%-12u,SYN:%u;PSH:%u;ACK:%u;FIN:%u;RST:%u; send!!!\n" // ,US_GET_LCORE(),trans_ip(iph->saddr),trans_ip(iph->daddr) // ,ntohs(th->source),ntohs(th->dest) // ,ntohl(th->seq),ntohl(th->ack_seq) // ,iph->id,skb->len,th->syn,th->psh,th->ack,th->fin,th->rst); if(n_ipv4->aft_route_out){ ret = n_ipv4->aft_route_out(skb); if(ret < 0) return US_ENETUNREACH; } // Send it out. return ip_local_out(skb); }
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; }