/*
* Function: RAW socket utility routines implementation:
*
* File Name: raw_gen.c
* Copyright by: no copyright
* Created by: Dangdanding
*
* Platform: Linux
* Version: 0.1v
* Make: gcc -Wall -c -DLINUX raw_gen.c
* ChangeLog:
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#if defined(LINUX)
#include <linux/tcp.h>
#else
#include <netinet/tcp.h>
#endif
#include "raw_gen.h"
#include "error.h"
//for LINUX
#ifndef IP_LEN_HORDER
#define IP_LEN_HORDER
#endif
/* psuedo header for UDP and TCP */
struct psuedohdr {
struct in_addr source_address;
struct in_addr dest_address;
unsigned char place_holder;
unsigned char protocol;
unsigned short length;
} psuedohdr;
/* Write out an IP header.*/
void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,
struct in_addr daddr,unsigned short length)
{
#if !defined(LINUX)
struct ip *iphdr;
#else
struct iphdr *iphdr;
#endif /* LINUX */
#if !defined(LINUX)
iphdr = (struct ip *)packet;
memset((char *)iphdr,'/0',sizeof(struct ip));
iphdr->ip_hl = 5;
iphdr->ip_v = IPVERSION;
#ifdef IP_LEN_HORDER
iphdr->ip_len = length;
#else
iphdr->ip_len = htons(length);
#endif /* IP_LEN_HORDER */
iphdr->ip_id = htons(getpid());
iphdr->ip_ttl = DEFAULT_TTL;
iphdr->ip_p = protocol;
iphdr->ip_src = saddr;
iphdr->ip_dst = daddr;
iphdr->ip_sum = (unsigned short)in_cksum((unsigned short *)iphdr,
sizeof(struct ip));
#else /* LINUX */
iphdr = (struct iphdr *)packet;
memset((char *)iphdr,'/0',sizeof(struct iphdr));
iphdr->ihl = 5;
iphdr->version = IPVERSION;
#ifdef IP_LEN_HORDER
iphdr->tot_len = length;
#else
iphdr->tot_len = htons(length);
#endif /* IP_LEN_HORDER */
//iphdr->id = htons(getpid());
iphdr->id = htons(random());
iphdr->ttl = DEFAULT_TTL;
iphdr->protocol = protocol;
iphdr->saddr = saddr.s_addr;
iphdr->daddr = daddr.s_addr;
iphdr->check = (unsigned short)in_cksum((unsigned short *)iphdr,
sizeof(struct iphdr));
#endif /* LINUX */
return;
} /* ip_gen() */
/* Write out a TCP header */
void tcp_gen(char *packet,unsigned short sport, unsigned short dport,
unsigned long seq, unsigned long ackseq,
u_int16_t fin,
u_int16_t syn,
u_int16_t rst,
u_int16_t ack,
u_int16_t psh,
u_int16_t urg)
{
struct tcphdr *tcp;
tcp = (struct tcphdr *)packet;
memset((char *)tcp,'/0',sizeof(struct tcphdr));
#if !defined(LINUX)
tcp->th_sport = htons(sport);
tcp->th_dport = htons(dport);
tcp->th_seq = htonl(seq);
tcp->th_ack = htonl(ack);
#ifdef X2_OFF
tcp->th_x2_off = TH_OFFSET;
#else /* X2_OFF */
tcp->th_off = TH_OFFSET;
tcp->th_x2 = 0;
#endif /* X2_OFF */
tcp->th_win = htons(TCP_WINDOW_SIZE);
tcp->th_flags = TH_FIN;
#else /* LINUX */
tcp->source = htons(sport);
tcp->dest = htons(dport);
tcp->seq = htonl(seq);
tcp->ack_seq = htonl(ackseq);
tcp->res1 = 0;
tcp->doff = TH_OFFSET;
tcp->window = htons(TCP_WINDOW_SIZE);
tcp->fin = fin;
tcp->syn = syn;
tcp->ack = ack;
tcp->psh = psh;
tcp->urg = rst;
tcp->urg = urg;
#endif /* LINUX */
return;
} /* tcp_gen() */
/* Write UDP header */
void udp_gen(char *packet,unsigned short sport,
unsigned short dport,unsigned short length)
{
struct udphdr *udp;
udp = (struct udphdr *)packet;
#if !defined(LINUX)
udp->uh_sport = htons(sport);
udp->uh_dport = htons(dport);
udp->uh_ulen = htons(length);
udp->uh_sum = 0;
#else /* LINUX */
udp->source = htons(sport);
udp->dest = htons(dport);
udp->len = htons(length);
udp->check = 0;
#endif /* LINUX */
return;
} /* udp_gen() */
/* transport layer header checksum */
unsigned short trans_check(unsigned char proto,
char *packet,
int length,
struct in_addr source_address,
struct in_addr dest_address)
{
char *psuedo_packet;
unsigned short answer;
psuedohdr.protocol = proto;
psuedohdr.length = htons(length);
psuedohdr.place_holder = 0;
psuedohdr.source_address = source_address;
psuedohdr.dest_address = dest_address;
if((psuedo_packet = malloc(sizeof(psuedohdr) + length)) == NULL) {
perror("malloc");
exit(1);
}
memcpy(psuedo_packet,&psuedohdr,sizeof(psuedohdr));
memcpy((psuedo_packet + sizeof(psuedohdr)),
packet,length);
answer = (unsigned short)in_cksum((unsigned short *)psuedo_packet,
(length + sizeof(psuedohdr)));
free(psuedo_packet);
return answer;
} /* trans_check() */
/*
* in_cksum --
* Checksum routine for Internet Protocol family headers (C Version)
*
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Muuss.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
unsigned short in_cksum(const unsigned short *addr,int len)
{
register int sum = 0;
u_short answer = 0;
const register u_short *w = addr;
register int nleft = len;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
extern void icmp_echo_gen(char *packet, uint8_t type, uint16_t id, uint16_t sequence, uint16_t datalen)
{
int len;
struct icmphdr *icmphdr = (struct icmphdr *)packet;
bzero(icmphdr, ICMPHDRS);
icmphdr->type = type;
//icmphdr->code = 0;
icmphdr->un.echo.sequence = sequence;
icmphdr->un.echo.id = id;
len = ICMPHDRS + datalen;
icmphdr->checksum = in_cksum((unsigned short *)icmphdr, len);
return;
}//generate icmp ECHO datagram
extern int get_raw_socket()
{
int sockfd;
int on =1;//for setsockopt()
if (-1 == (sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))) {
err_sys("send_raw_tcp: ", "socket() error!");
}
//set ip options
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
err_sys("send_raw_tcp: ", "setsockopt() error!");
}
return sockfd;
}//end of get_raw_socket()