I was able to get it working, but its pretty rough stage. I hope to clean it up a little better, and make it look pretty. Also it needs a lot more error checking.
The source IP, source port, seq, destionation IP, destination port, and ack seq are all passed into the function. It allocates a new sk_buff, and starts populating the required data. The real trick is that you have to populate the skb->dst structure, and the skb->dev structure or the sk_buff will not send it will actually crash the system is my experiance.
To do that I used ip_route_input(). Only it requires an inbound device to calculate the route. I tried to find something that did not require a device to calculate the route, but could not find anything.
The second function is something I already had that could get a network device by name. I am already using the IP on this device in my module so I just save the device to a global pointer "struct net_device *device", and use this each time I send a keepalive to calculate the route.
This could be modified pretty easily to send TCP packets with data in them, but I just needed it to send keepalive messages.
Code:
void sendkeepalive
(__u32 saddr, __u16 source, __u32 seq,
__u32 daddr, __u16 dest, __u32 ack_seq
){
struct sk_buff *skb = NULL;
struct iphdr *iph = NULL;
struct tcphdr *tcph = NULL;
printk(KERN_ALERT "Device index: %u.\n",
netdevice->ifindex);
skb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr), GFP_ATOMIC); // Allocate a new sk_buff with room for L2 header.
if (skb == NULL){
return;
}
skb->protocol = __constant_htons(ETH_P_IP); // This is an IP packet.
skb->pkt_type = PACKET_OUTGOING; // Its outgoing.
skb->ip_summed = CHECKSUM_NONE; // No need to checksum.
skb->nh.raw = skb->data; // Not sure if this is needed.
skb_reserve(skb, sizeof(struct iphdr) + sizeof(struct tcphdr)); // Reserve the space for the L3, and L4 headers.
tcph = (struct tcphdr *)skb_push(skb, sizeof(struct tcphdr)); // Setup pointer for the L4 header.
iph = (struct iphdr *)skb_push(skb, sizeof(struct iphdr)); // Setup pointer for the L3 header.
iph->ihl = 5; // IP header length.
iph->version = 4; // IPv4.
iph->tos = 0; // No TOS.
iph->tot_len=htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); // L3 + L4 header length.
iph->id = 0; // What?
iph->frag_off = 0; // No fragmenting.
iph->ttl = 64; // Set a TTL.
iph->protocol = IPPROTO_TCP; // TCP protocol.
iph->check = 0; // No IP checksum yet.
iph->saddr = saddr; // Source IP.
iph->daddr = daddr; // Dest IP.
tcph->check = 0; // No TCP checksum yet.
tcph->source = source; // Source TCP Port.
tcph->dest = dest; // Destination TCP Port.
tcph->seq = htonl(seq - 1); // Current SEQ minus one is used for TCP keepalives.
tcph->ack_seq = htonl( ack_seq - 1); // Ummm not sure yet.
tcph->res1 = 0; // Not sure.
tcph->doff = 5; // TCP Offset. At least 5 if there are no TCP options.
tcph->fin = 0; // FIN flag.
tcph->syn = 0; // SYN flag.
tcph->rst = 0; // RST flag.
tcph->psh = 0; // PSH flag.
tcph->ack = 1; // ACK flag.
tcph->urg = 0; // URG flag.
tcph->ece = 0; // ECE flag? It should be 0.
tcph->cwr = 0; // CWR flag? It should be 0.
ip_route_input(skb, daddr, saddr, iph->tos, netdevice); // Populate the skb->dst structure.
ip_send_check(iph); // Calulcate an IP checksum.
skb->dev = skb->dst->dev; // Populate skb->dev or it wont send.
printk(KERN_ALERT "SKB device index: %u.\n",
skb->dev->ifindex);
printk(KERN_ALERT "Route device index: %u.\n",
skb->dst->dev->ifindex);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); // Sent the packet.
return;
}
Code:
static inline void
getlocalIP(void){
struct net_device *eth0;
struct in_device *in_dev;
struct in_ifaddr *if_addr;
char dev_name[20];
__u32 eth0IP;
__u8 *addr;
eth0IP = 0;
sprintf(dev_name,"eth%d",0);
eth0 = dev_get_by_name(dev_name);
netdevice = eth0; // Sets the device used to send TCP keepalives.
in_dev = (struct in_device *)eth0->ip_ptr;
if_addr = in_dev->ifa_list;
addr = (char *)&if_addr->ifa_local;
eth0IP += (addr[0] << 24);
eth0IP += (addr[1] << 16);
eth0IP += (addr[2] << 8);
eth0IP += addr[3];
localIP = eth0IP;
return;
}