您的位置:首页 > 运维架构 > Linux

[转]Linux: ubuntu 9.10 10.04 下 安装 Dr.com 上网

2010-01-13 10:55 405 查看
想正式地试用一下ubuntu,装了9.10 ,分10G的空间,勉强足够,为了搭建一个PHP开发平台。

学校是电子科技大学中山学院,上网的方式是dr.com认证,windows下的版本是3.46,我自己改了一下,可以用内网。

wubi安装方式,上网搜索的教程,发现需要安装build-essential 来编译dr.com,后来找到了这个网站:

www.drcom-client.org

发现有带gui的,就下载安装。

先下载了drcom-client PUM v1.0
,deb包,直接安装,GUI可以出来,填好后点登录,出错,提示没有运行drcom的内核。

只好再下载drcom-client v1.4.8.2
命令行方式的来安装。

解压后,控制台下进入目录,输入

make

提示出错,后来再google讨论组里找到一个主题,也是有人讨论这个问题,貌似是因为新内核的原因。帖子里有
人修改了kmod目录下的drcom.c文件


并提供下载。下载覆盖后

make

sudo make install

一切正常,提示修改/etc/drcom.conf文件,配置登陆器。

drcom.conf文件在安装之后要手动设置,其中我们学校的设置就是如下

username=上网帐号

password=密码

nic0=你的IP

dnsp=这里是DNS1

dnss=这里是DNS2

hostip=这里填登陆学校Dr.com的服务器IP 不是windows系统中的1.1.1.1而是192.168.6.241

配置好后就可以了,打开GUI填好帐号密码登录就好。

---------------------------------------------------------------------------------------------------------------------------

Edit 2010-3-15

鉴于有读者在本文下面的评论中表示很需要kmod下的drcom.c文件, 我现在把它贴在下面,在此感谢为我们修改这份代码的朋友。

请把文件取名为drcom.c,并放在kmod文件下。

/*drcom.c*/
/*
* (C) 2008 Zeng Zhaorong
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* Derived from linux netfilter conntrack codes
*/
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#endif
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
#define nf_proto_csum_replace4	inet_proto_csum_replace4
#define NF_IP_PRE_ROUTING	NF_INET_PRE_ROUTING
#define NF_IP_POST_ROUTING	NF_INET_POST_ROUTING
#endif
#include "daemon_kernel.h"
#define TCPTRACK_VERSION "0.0.1"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wheelz");
MODULE_DESCRIPTION("Drcom-Kernel " TCPTRACK_VERSION);
enum tcp_state {
TCP_STATE_NONE = 0,
TCP_STATE_SYN_SENT,
TCP_STATE_SYN_RECV,
TCP_STATE_ESTABLISHED,
TCP_STATE_FIN_WAIT,
TCP_STATE_TIME_WAIT,
TCP_STATE_CLOSE,
TCP_STATE_CLOSE_WAIT,
TCP_STATE_LAST_ACK,
TCP_STATE_LISTEN,
TCP_STATE_MAX
};
#define SECS *HZ
#define MINS * 60 SECS
#define HOURS * 60 MINS
#define DAYS * 24 HOURS
static unsigned long tcp_timeouts[]
= { 30 MINS,    /*      TCP_STATE_NONE, */
2 MINS,     /*      TCP_STATE_SYN_SENT,     */
60 SECS,    /*      TCP_STATE_SYN_RECV,     */
5 DAYS,     /*      TCP_STATE_ESTABLISHED,  */
2 MINS,     /*      TCP_STATE_FIN_WAIT,     */
2 MINS,     /*      TCP_STATE_TIME_WAIT,    */
10 SECS,    /*      TCP_STATE_CLOSE,	*/
60 SECS,    /*      TCP_STATE_CLOSE_WAIT,   */
30 SECS,    /*      TCP_STATE_LAST_ACK,     */
2 MINS,     /*      TCP_STATE_LISTEN,       */
};
#define sNO TCP_STATE_NONE
#define sES TCP_STATE_ESTABLISHED
#define sSS TCP_STATE_SYN_SENT
#define sSR TCP_STATE_SYN_RECV
#define sFW TCP_STATE_FIN_WAIT
#define sTW TCP_STATE_TIME_WAIT
#define sCL TCP_STATE_CLOSE
#define sCW TCP_STATE_CLOSE_WAIT
#define sLA TCP_STATE_LAST_ACK
#define sLI TCP_STATE_LISTEN
#define sIV TCP_STATE_MAX
static enum tcp_state tcp_states[2][5][TCP_STATE_MAX] = {
{
/*      ORIGINAL */
/*	sNO, sSS, sSR, sES, sFW, sTW, sCL, sCW, sLA, sLI      */
/*syn*/ {sSS, sSS, sSR, sES, sSS, sSS, sSS, sSS, sSS, sLI },
/*fin*/ {sTW, sSS, sTW, sFW, sFW, sTW, sCL, sTW, sLA, sLI },
/*ack*/ {sES, sSS, sES, sES, sFW, sTW, sCL, sCW, sLA, sES },
/*rst*/ {sCL, sSS, sCL, sCL, sCL, sTW, sCL, sCL, sCL, sCL },
/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
},
{
/*      REPLY */
/*	sNO, sSS, sSR, sES, sFW, sTW, sCL, sCW, sLA, sLI      */
/*syn*/ {sSR, sSR, sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR },
/*fin*/ {sCL, sSS, sTW, sCW, sTW, sTW, sCL, sCW, sLA, sLI },
/*ack*/ {sCL, sSS, sSR, sES, sFW, sTW, sCL, sCW, sCL, sLI },
/*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI },
/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
}
};
struct tcp_tuple
{
__be32	src_ip;
__be32	dst_ip;
__be16	src_port;
__be16	dst_port;
u_int8_t	dir;
};
struct tcp_tuplehash
{
struct list_head 	list;
struct tcp_tuple	tuple;
};
struct tcp_seq
{
u_int32_t	syn_seq;
u_int32_t	correction_pos;
int16_t 	offset_before, offset_after;
};
struct tcp_conn
{
struct tcp_tuplehash	tuplehash[2];
atomic_t 		ref;
struct timer_list	timeout;
u_int8_t		flags;
enum tcp_state		state;
struct tcp_seq		seq[2];
};
#define CONN_F_NEW	0x01
#define CONN_F_AUTHSENT	0x02
#define TODO_NONE	0x00
#define TODO_ADJUST_SEQ	0x01
#define TODO_SEND_ACK	0x02
#define TODO_SEND_AUTH	0x04
#define CONN_DIR_ORIG	0
#define CONN_DIR_REPLY	1
#define TCP_CONN_HASH_SIZE	32
static pid_t	conn_pid = 0;
static int	conn_autologout = 0;
static struct timer_list conn_keepalive_timer;
static unsigned char conn_auth_data[CONN_AUTH_DATA_LEN];
static struct list_head		tcp_conn_hash[TCP_CONN_HASH_SIZE];
static atomic_t	tcp_conn_count = ATOMIC_INIT(0);
static struct net_device 	*track_dev = NULL;
static struct e_address		*conn_e_addr = NULL;
static int conn_e_count = 0;
static int track_mode = CONN_MODE_NONE;
static DEFINE_RWLOCK(mode_lock);
static DEFINE_RWLOCK(hash_lock);
static DEFINE_RWLOCK(state_lock);
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
#if 0
static const char *tcp_state_names[] = {
"NONE",
"SYN_SENT",
"SYN_RECV",
"ESTABLISHED",
"FIN_WAIT",
"TIME_WAIT",
"CLOSE",
"CLOSE_WAIT",
"LAST_ACK",
"LISTEN"
};
#endif
static inline int tuple_equal(struct tcp_tuple *t1, struct tcp_tuple *t2)
{
return (t1->src_ip == t2->src_ip && t1->dst_ip == t2->dst_ip
&& t1->src_port == t2->src_port && t1->dst_port == t2->dst_port);
}
static inline u_int32_t hash_conn(const struct tcp_tuple *tuple)
{
return (ntohl(tuple->src_ip + tuple->dst_ip + tuple->src_port + tuple->dst_port)
+ ntohs(tuple->src_port)) % TCP_CONN_HASH_SIZE;
}
static inline struct tcp_conn *tuplehash_to_conn(const struct tcp_tuplehash *hash)
{
return container_of(hash, struct tcp_conn, tuplehash[hash->tuple.dir]);
}
static inline void conn_get(struct tcp_conn *conn)
{
if (conn)
atomic_inc(&conn->ref);
}
static inline void conn_put(struct tcp_conn *conn)
{
if (conn && atomic_dec_and_test(&conn->ref)) {
kfree(conn);
atomic_dec(&tcp_conn_count);
}
}
/* under state_lock */
static void __conn_refresh_timer(struct tcp_conn *conn, unsigned long timeout)
{
unsigned long newtime;
if (conn->flags & CONN_F_NEW) {
conn->flags &= ~CONN_F_NEW;
conn->timeout.expires = jiffies + timeout;
add_timer(&conn->timeout);
} else {
newtime = jiffies + timeout;
if (newtime - conn->timeout.expires >= HZ && del_timer(&conn->timeout)) {
conn->timeout.expires = newtime;
add_timer(&conn->timeout);
}
}
}
static void death_by_timeout(unsigned long ul_conn)
{
struct tcp_conn *conn = (struct tcp_conn*)ul_conn;
write_lock_bh(&hash_lock);
list_del(&conn->tuplehash[CONN_DIR_ORIG].list);
list_del(&conn->tuplehash[CONN_DIR_REPLY].list);
write_unlock_bh(&hash_lock);
conn_put(conn);
}
static void conn_tuple_init(struct tcp_conn *conn, struct tcp_tuple *tuple)
{
struct tcp_tuple *t;
t = &conn->tuplehash[CONN_DIR_ORIG].tuple;
t->src_ip = tuple->src_ip;
t->dst_ip = tuple->dst_ip;
t->src_port = tuple->src_port;
t->dst_port = tuple->dst_port;
t->dir = CONN_DIR_ORIG;

t = &conn->tuplehash[CONN_DIR_REPLY].tuple;
t->src_ip = tuple->dst_ip;
t->dst_ip = tuple->src_ip;
t->src_port = tuple->dst_port;
t->dst_port = tuple->src_port;
t->dir = CONN_DIR_REPLY;
}
static inline struct tcp_conn *get_new_conn(struct tcp_tuple *tuple)
{
struct tcp_conn *conn;
conn = kmalloc(sizeof(struct tcp_conn), GFP_ATOMIC);
if (conn == NULL)
return NULL;
memset(conn, 0, sizeof(struct tcp_conn));
conn->flags = CONN_F_NEW;
conn_tuple_init(conn, tuple);
setup_timer(&conn->timeout, death_by_timeout, (unsigned long)conn);
return conn;
}
static int is_syn_pkt(struct sk_buff *skb)
{
unsigned int nhoff = skb_network_offset(skb);
struct iphdr *iph, _iph;
struct tcphdr *tcph, _tcph;
iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
if (iph == NULL)
return 0;
tcph = skb_header_pointer(skb, nhoff + (iph->ihl << 2), sizeof(_tcph), &_tcph);
if (tcph == NULL)
return 0;
return (tcph->syn && !tcph->ack);
}
static int tcp_get_tuple(struct sk_buff *skb, struct tcp_tuple *tuple)
{
struct iphdr _iph, *iph;
struct tcphdr _hdr, *hp;
unsigned int nhoff = skb_network_offset(skb);
unsigned int thoff;
memset(tuple, 0, sizeof(struct tcp_tuple));
iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
if (iph == NULL)
return 0;
tuple->src_ip = iph->saddr;
tuple->dst_ip = iph->daddr;
thoff = nhoff + (iph->ihl << 2);
hp = skb_header_pointer(skb, thoff, 8, &_hdr);
if (hp == NULL)
return 0;
tuple->src_port = hp->source;
tuple->dst_port = hp->dest;
return 1;
}
static inline void __add_new_hash(struct tcp_tuplehash *hash)
{
u_int32_t h = hash_conn(&hash->tuple);
struct list_head *head = &tcp_conn_hash[h];
list_add_tail(&hash->list, head);
}
static struct tcp_tuplehash *__hash_find(struct tcp_tuple *tuple)
{
struct tcp_tuplehash *tuplehash;
struct list_head *head, *pos;
u_int32_t h;
h = hash_conn(tuple);
head = &tcp_conn_hash[h];
list_for_each(pos, head) {
tuplehash = list_entry(pos, struct tcp_tuplehash, list);
if (tuple_equal(&tuplehash->tuple, tuple))
return tuplehash;
}
return NULL;
}
static struct tcp_tuplehash *resolve_tcp_conn(struct sk_buff *skb)
{
struct tcp_tuple tuple;
struct tcp_conn *conn;
struct tcp_tuplehash *hash;
if (!tcp_get_tuple(skb, &tuple))
return NULL;
read_lock_bh(&hash_lock);
hash = __hash_find(&tuple);
if (hash != NULL) {
conn = tuplehash_to_conn(hash);
conn_get(conn);
read_unlock_bh(&hash_lock);
return hash;
}
read_unlock_bh(&hash_lock);
/* OK, This is a new connection, let's create a conn */
/* the first packet must be SYN && !ACK */
if (!is_syn_pkt(skb))
return NULL;
conn = get_new_conn(&tuple);
if (conn == NULL)
return NULL;
conn_get(conn);/* for this packet */
conn_get(conn);/* for hash list */
write_lock_bh(&hash_lock);
hash = __hash_find(&tuple);
if (hash != NULL) { /* already added by someone else, but is it possible?  */
struct tcp_conn *conn2 = tuplehash_to_conn(hash);
conn_get(conn2);
write_unlock_bh(&hash_lock);
conn_put(conn); /* for hash list */
conn_put(conn); /* for this packet */
return hash;
}
__add_new_hash(&conn->tuplehash[CONN_DIR_ORIG]);
__add_new_hash(&conn->tuplehash[CONN_DIR_REPLY]);

write_unlock_bh(&hash_lock);
atomic_inc(&tcp_conn_count);
hash = &conn->tuplehash[CONN_DIR_ORIG];
return hash;
}
static void sack_adjust(struct sk_buff *skb, struct tcphdr *tcph,
unsigned int sackoff, unsigned int sackend, struct tcp_seq *seq)
{
while (sackoff < sackend) {
struct tcp_sack_block_wire *sack;
__be32 new_start_seq, new_end_seq;
sack = (void *)skb->data + sackoff;
if (after(ntohl(sack->start_seq) - seq->offset_before, seq->correction_pos))
new_start_seq = htonl(ntohl(sack->start_seq) - seq->offset_after);
else
new_start_seq = htonl(ntohl(sack->start_seq) - seq->offset_before);
if (after(ntohl(sack->end_seq) - seq->offset_before, seq->correction_pos))
new_end_seq = htonl(ntohl(sack->end_seq) - seq->offset_after);
else
new_end_seq = htonl(ntohl(sack->end_seq) - seq->offset_before);
DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d/n",
ntohl(sack->start_seq), ntohl(new_start_seq), ntohl(sack->end_seq), ntohl(new_end_seq));
nf_proto_csum_replace4(&tcph->check, skb, sack->start_seq, new_start_seq, 0);
nf_proto_csum_replace4(&tcph->check, skb, sack->end_seq, new_end_seq, 0);
sack->start_seq = new_start_seq;
sack->end_seq = new_end_seq;
sackoff += sizeof(*sack);
}
}
static int tcp_sack_adjust(struct tcp_conn *conn, int dir, struct sk_buff *skb, struct tcphdr *tcph)
{
unsigned int optoff, optend;
optoff = ip_hdrlen(skb) + sizeof(struct tcphdr);
optend = ip_hdrlen(skb) + tcph->doff * 4;
if (!skb_make_writable(skb, optend))
return 0;
while (optoff < optend) {
/* Usually: option, length. */
unsigned char *op = skb->data + optoff;
switch (op[0]) {
case TCPOPT_EOL:
return 1;
case TCPOPT_NOP:
optoff++;
continue;
default:
/* no partial options */
if (optoff + 1 == optend || optoff + op[1] > optend || op[1] < 2)
return 0;
if (op[0] == TCPOPT_SACK && op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
sack_adjust(skb, tcph, optoff+2, optoff+op[1], &conn->seq[!dir]);
optoff += op[1];
}
}
return 1;
}
static int tcp_adjust_seq(struct sk_buff *skb, struct tcp_tuplehash *hash)
{
struct tcp_conn *conn = tuplehash_to_conn(hash);
int dir = hash->tuple.dir;
struct tcphdr *tcph;
__be32 newseq, newack;
struct tcp_seq *this_way, *other_way;
int ret = 0;
read_lock_bh(&state_lock);
this_way = &conn->seq[dir];
other_way = &conn->seq[!dir];
if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
goto out;
tcph = (void *)skb->data + ip_hdrlen(skb);
if (after(ntohl(tcph->seq), this_way->correction_pos))
newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
else
newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
if (after(ntohl(tcph->ack_seq) - other_way->offset_before, other_way->correction_pos))
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
else
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
if (newseq != tcph->seq) {
nf_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
tcph->seq = newseq;
}
if (newack != tcph->ack_seq) {
nf_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
tcph->ack_seq = newack;
if (!tcp_sack_adjust(conn, dir, skb, tcph))
goto out;
}
ret = 1;
out:
read_unlock_bh(&state_lock);
return ret;
}
static unsigned int get_state_index(const struct tcphdr *tcph)
{
if (tcph->rst) {return 3;}
else if (tcph->syn) {return 0;}
else if (tcph->fin) {return 1;}
else if (tcph->ack) {return 2;}
else {return 4;}
}
/* return what to do */
static unsigned int check_tcp_packet(struct sk_buff *skb, struct tcp_tuplehash *hash)
{
enum tcp_state newstate, oldtcpstate;
struct tcp_conn *conn = tuplehash_to_conn(hash);
int dir = hash->tuple.dir;
unsigned int nhoff = skb_network_offset(skb);
struct iphdr *iph, _iph;
struct tcphdr *tcph, _tcph;
unsigned int hdrlen;
struct tcp_seq *seq;
u_int8_t todo = TODO_NONE;
iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
if (iph == NULL)
return TODO_NONE;
tcph = skb_header_pointer(skb, nhoff + (iph->ihl << 2), sizeof(_tcph), &_tcph);
if (tcph == NULL)
return TODO_NONE;
hdrlen = (iph->ihl + tcph->doff)*4;
if (skb->len < hdrlen) {/* we may not have the options */
DEBUGP("tcp_packet: Truncated packet./n");
return TODO_NONE;
}
write_lock_bh(&state_lock);
oldtcpstate = conn->state;
newstate = tcp_states[dir][get_state_index(tcph)][oldtcpstate];
if (newstate == TCP_STATE_MAX) { /* invalid */
DEBUGP("tcp_packet: Invalid dir=%i index=%u state=%s/n",
dir, get_state_index(tcph), tcp_state_names[conn->state]);
write_unlock_bh(&state_lock);
return TODO_NONE;
}
conn->state = newstate;
if (conn->flags & CONN_F_AUTHSENT) {
todo = TODO_ADJUST_SEQ;
goto out;
}
/* Handshake SYN */
if (oldtcpstate == TCP_STATE_NONE && dir == CONN_DIR_ORIG && tcph->syn && !tcph->ack) {
seq = &conn->seq[dir];
seq->syn_seq = ntohl(tcph->seq);
seq->correction_pos = seq->syn_seq;
seq->offset_before = 0;
seq->offset_after = CONN_AUTH_DATA_LEN;
todo = TODO_NONE;
goto out;
}
/* Handshake SYN-ACK */
if (oldtcpstate == TCP_STATE_SYN_SENT && dir == CONN_DIR_REPLY && tcph->syn && tcph->ack) {
seq = &conn->seq[dir];
seq->syn_seq = ntohl(tcph->seq);
seq->correction_pos = seq->syn_seq;
seq->offset_before = 0;
seq->offset_after = 0;
todo = TODO_NONE;
goto out;
}
/* Handshake pure ACK: we don't care this case actually */
/*
if (oldtcpstate == TCP_STATE_SYN_RECV && skb->len == hdrlen && dir == CONN_DIR_ORIG
&& tcph->ack && !tcph->syn && ntohl(tcph->ack_seq) == conn->seq[!dir].syn_seq+1)
{
todo = TODO_NONE;
goto out;
}
*/
/* Handshake ACK with data*/
if (oldtcpstate == TCP_STATE_SYN_RECV && skb->len > hdrlen && dir == CONN_DIR_ORIG
&& tcph->ack && !tcph->syn
&& (ntohl(tcph->ack_seq) == conn->seq[!dir].syn_seq+1)
&& (ntohl(tcph->seq) == conn->seq[dir].syn_seq+1)
&& !(conn->flags & CONN_F_AUTHSENT))
{
todo = TODO_SEND_ACK | TODO_SEND_AUTH | TODO_ADJUST_SEQ;
conn->flags |= CONN_F_AUTHSENT;
goto out;
}
/* The first data packet */
if (oldtcpstate == TCP_STATE_ESTABLISHED && skb->len > hdrlen && dir == CONN_DIR_ORIG
&& tcph->ack && !tcph->syn
/*    && (ntohl(tcph->ack_seq) == conn->seq[!dir].syn_seq+1) *//* ftp server will send first */
&& (ntohl(tcph->seq) == conn->seq[dir].syn_seq+1)
&& !(conn->flags & CONN_F_AUTHSENT))
{
todo = TODO_SEND_AUTH | TODO_ADJUST_SEQ;
conn->flags |= CONN_F_AUTHSENT;
goto out;
}
/*
* CONN_F_AUTHSENT not set,
* and not the case to set CONN_F_AUTHSENT,
* just bypass
*/
todo = TODO_NONE;
out:
__conn_refresh_timer(conn, tcp_timeouts[newstate]);
write_unlock_bh(&state_lock);
return todo;
}
static struct sk_buff *build_ack_skb(struct sk_buff *oskb)
{
struct iphdr *iph;
struct tcphdr *tcph;
struct sk_buff *skb;
/* FIXME: Can we avoid the copy here? */
skb = skb_copy(oskb, GFP_ATOMIC);
if (skb == NULL)
return NULL;
iph = ip_hdr(skb);
tcph = (void *)skb->data + ip_hdrlen(skb);
skb_trim(skb, (iph->ihl + tcph->doff) * 4);
skb_shinfo(skb)->gso_segs = 1;
skb_shinfo(skb)->gso_size = 0;
skb_shinfo(skb)->gso_type = 0;
skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0;
tcph->check = 0;
tcph->check = tcp_v4_check(tcph->doff << 2, iph->saddr, iph->daddr,
csum_partial((char *)tcph, tcph->doff << 2, skb->csum));
iph->tot_len = htons(skb->len);
__ip_select_ident(iph, skb_dst(skb), 0);
ip_send_check(iph);
return skb;
}
static struct sk_buff *build_auth_skb(struct sk_buff *oskb)
{
struct iphdr *iph;
struct tcphdr *tcph;
unsigned int hdrlen;
struct sk_buff *skb;
/* FIXME: Can we avoid the copy here? */
skb = skb_copy_expand(oskb, skb_headroom(oskb), CONN_AUTH_DATA_LEN, GFP_ATOMIC);
if (skb == NULL)
return NULL;
iph = ip_hdr(skb);
tcph = (void *)skb->data + ip_hdrlen(skb);
hdrlen = (iph->ihl + tcph->doff) * 4;
skb_trim(skb, hdrlen);
skb_put(skb, CONN_AUTH_DATA_LEN);
memcpy(skb->data + hdrlen, conn_auth_data, CONN_AUTH_DATA_LEN);
skb_shinfo(skb)->gso_segs = 1;
skb_shinfo(skb)->gso_size = 0;
skb_shinfo(skb)->gso_type = 0;
skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0;
tcph->check = 0;
tcph->check = tcp_v4_check(skb->len-ip_hdrlen(skb), iph->saddr, iph->daddr,
csum_partial((char *)tcph, skb->len-ip_hdrlen(skb), skb->csum));
iph->tot_len = htons(skb->len);
__ip_select_ident(iph, skb_dst(skb), 0);
ip_send_check(iph);
return skb;
}
static inline int is_our_packet(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
return (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP);
}
static inline int is_udp_packet(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
return (iph->protocol == IPPROTO_UDP);
}
static void conn_do_udp(struct sk_buff *oskb, int (*okfn)(struct sk_buff *))
{
struct sk_buff *skb;
struct iphdr *iph;
struct udphdr *udph;
unsigned short len;
/* FIXME: Can we avoid the copy here? */
skb = skb_copy_expand(oskb, skb_headroom(oskb) + CONN_AUTH_DATA_LEN, 0, GFP_ATOMIC);
if (skb == NULL)
return;
kfree_skb(oskb);
iph = ip_hdr(skb);
udph = (void *)iph + ip_hdrlen(skb);
memcpy((void *)iph-CONN_AUTH_DATA_LEN, (void*)iph, ip_hdrlen(skb)+8);
memcpy((void*)udph+8-CONN_AUTH_DATA_LEN, conn_auth_data, CONN_AUTH_DATA_LEN);
skb_push(skb, CONN_AUTH_DATA_LEN);
skb_reset_network_header(skb);
iph = ip_hdr(skb);
udph = (void *)iph + ip_hdrlen(skb);
skb_shinfo(skb)->gso_segs = 1;
skb_shinfo(skb)->gso_size = 0;
skb_shinfo(skb)->gso_type = 0;
skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0;
len = ntohs(udph->len) + CONN_AUTH_DATA_LEN;
udph->len = htons(len);
udph->check = 0;
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, len, IPPROTO_UDP,
csum_partial((unsigned char *)udph, len, 0));
/* ip stuff */
iph->tot_len = htons(skb->len);
ip_send_check(iph);
okfn(skb);
}
static int need_auth_input(struct sk_buff *skb)
{
u_int32_t saddr = ip_hdr(skb)->saddr;
int i;
for (i=0; i<conn_e_count; i++)
if ((conn_e_addr[i].mask & saddr) == conn_e_addr[i].addr)
return 0;
return 1;
}
static int need_auth_output(struct sk_buff *skb)
{
u_int32_t daddr = ip_hdr(skb)->daddr;
int i;
for (i=0; i<conn_e_count; i++)
if ((conn_e_addr[i].mask & daddr) == conn_e_addr[i].addr)
return 0;
return 1;
}
#define CONN_KEEPALIVE_TIMEOUT	(2*60*HZ)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
#define kill_proc(pid, sig, priv)	kill_pid(find_vpid(pid), sig, priv)
#endif
static void keepalive_func(unsigned long ul)
{
read_lock_bh(&mode_lock);
if (track_mode != CONN_MODE_NONE && conn_autologout && conn_pid)
kill_proc(conn_pid, SIGUSR1, 1);
read_unlock_bh(&mode_lock);
}
static void init_keepalive_timer(void)
{
read_lock_bh(&mode_lock);
if (track_mode != CONN_MODE_NONE && conn_autologout) {
setup_timer(&conn_keepalive_timer, keepalive_func, 0);
conn_keepalive_timer.expires = jiffies+CONN_KEEPALIVE_TIMEOUT;
add_timer(&conn_keepalive_timer);
}
read_unlock_bh(&mode_lock);
}
/* under mode_lock */
static void __refresh_keepalive_timer(void)
{
if (conn_autologout)
mod_timer(&conn_keepalive_timer, jiffies+CONN_KEEPALIVE_TIMEOUT);
}
static void del_keepalive_timer(void)
{
read_lock_bh(&mode_lock);
del_timer(&conn_keepalive_timer);
read_unlock_bh(&mode_lock);
}
static unsigned int preroute_hook(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct tcp_tuplehash *hash;
unsigned int todo;
read_lock_bh(&mode_lock);
if (track_mode == CONN_MODE_NONE)
goto out_unlock;
if (in != track_dev || !is_our_packet(skb))
goto out_unlock;
if (!need_auth_input(skb))
goto out_unlock;
__refresh_keepalive_timer();
if (is_udp_packet(skb)) {
/*
* we need do nothing here
*/
read_unlock_bh(&mode_lock);
return NF_ACCEPT;
}
hash = resolve_tcp_conn(skb);
if (hash == NULL)
goto out_unlock;
todo = check_tcp_packet(skb, hash);
if (todo & TODO_ADJUST_SEQ)
(void)tcp_adjust_seq(skb, hash);
conn_put(tuplehash_to_conn(hash));
out_unlock:
read_unlock_bh(&mode_lock);
return NF_ACCEPT;
}
static unsigned int postroute_hook(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct tcp_tuplehash *hash;
unsigned int todo;
struct sk_buff *skb2;
read_lock_bh(&mode_lock);
if (track_mode == CONN_MODE_NONE)
goto out_unlock;
if (out != track_dev || !is_our_packet(skb))
goto out_unlock;
if (!need_auth_output(skb))
goto out_unlock;
__refresh_keepalive_timer();
if (is_udp_packet(skb)) {
conn_do_udp(skb, okfn);
read_unlock_bh(&mode_lock);
return NF_STOLEN;
}
hash = resolve_tcp_conn(skb);
if (hash == NULL)
goto out_unlock;
todo = check_tcp_packet(skb, hash);
if (todo & TODO_SEND_ACK) {
skb2 = build_ack_skb(skb);
if (skb2 != NULL)
okfn(skb2);
}
if (todo & TODO_SEND_AUTH) {
skb2 = build_auth_skb(skb);
if (skb2 != NULL)
okfn(skb2);
}
if (todo & TODO_ADJUST_SEQ)
(void)tcp_adjust_seq(skb, hash);
conn_put(tuplehash_to_conn(hash));
out_unlock:
read_unlock_bh(&mode_lock);
return NF_ACCEPT;
}
static struct nf_hook_ops preroute_hook_ops = {
.hook = preroute_hook,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG+1,
};
static struct nf_hook_ops postroute_hook_ops = {
.hook = postroute_hook,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_POST_ROUTING,
.priority = NF_IP_PRI_LAST,
};
static void conn_hash_cleanup(void)
{
struct tcp_conn *conn;
struct tcp_tuplehash *h;
int i;
/* free tcp_conn hash memory */
i_see_dead_people:
while (1) {
conn = NULL;
write_lock_bh(&hash_lock);
for (i=0; i<TCP_CONN_HASH_SIZE; i++) {
struct list_head *head = &tcp_conn_hash[i];
if (!list_empty(head)){
h = list_entry(head->next, struct tcp_tuplehash, list);
conn = tuplehash_to_conn(h);
conn_get(conn);
break;
}
}
write_unlock_bh(&hash_lock);
if (conn == NULL)
break;
if (del_timer(&conn->timeout)) {
death_by_timeout((unsigned long)conn);
conn_put(conn);
}
}
while (atomic_read(&tcp_conn_count) != 0) {
schedule();
goto i_see_dead_people;
}
}
static int conn_hooks_init(void)
{
int ret;
ret = nf_register_hook(&preroute_hook_ops);
if(ret < 0){
printk(KERN_ERR "PRE-ROUTE hook register failed/n");
goto out_err;
}
ret = nf_register_hook(&postroute_hook_ops);
if(ret < 0){
printk(KERN_ERR "POST-ROUTE hook register failed/n");
goto out_unregister_1;
}
return 0;
out_unregister_1:
nf_unregister_hook(&preroute_hook_ops);
out_err:
return ret;
}
static void conn_hooks_cleanup(void)
{
nf_unregister_hook(&postroute_hook_ops);
nf_unregister_hook(&preroute_hook_ops);
synchronize_net();
}
static int conn_set_params(struct sock *sk, int optname, void *optval, unsigned int optlen)
{
struct conn_param cp;
struct net_device *dev, *tmp_dev = NULL;
struct e_address *e_addr=NULL, *tmp_addr;
unsigned int e_len;
int i;
if (optlen < sizeof(struct conn_param))
return -EINVAL;
if (copy_from_user(&cp, optval, sizeof(struct conn_param)))
return -EFAULT;
if (cp.e_count < 0)
return -EINVAL;
if (cp.e_count > 0) {
e_len = cp.e_count * sizeof(struct e_address);
if (optlen < sizeof(struct conn_param) + e_len)
return -EINVAL;
e_addr = kmalloc(e_len, GFP_KERNEL);
if (e_addr == NULL)
return -ENOMEM;
if (copy_from_user(e_addr, optval+sizeof(struct conn_param), e_len)) {
kfree(e_addr);
return -EFAULT;
}
}
dev = dev_get_by_name(&init_net, cp.devname);
if (dev == NULL) {
if (e_addr)
kfree(e_addr);
return -ENODEV;
}
write_lock_bh(&mode_lock);
tmp_addr = conn_e_addr;
conn_e_count = cp.e_count;
if (conn_e_count != 0) {
conn_e_addr = e_addr;
for(i=0; i<conn_e_count; i++)
conn_e_addr[i].addr &= conn_e_addr[i].mask;
}
tmp_dev = track_dev;
track_dev = dev;
write_unlock_bh(&mode_lock);
if (tmp_addr)
kfree(tmp_addr);
if (tmp_dev)
dev_put(tmp_dev);
return 0;
}
static int conn_set_auth_cmd(struct sock *sk, int optname, void *optval, unsigned int optlen)
{
struct conn_auth_cmd cmd;
int hash_todo = 0;
if (optlen < sizeof(struct conn_auth_cmd))
return -EINVAL;
if (copy_from_user(&cmd, optval, sizeof(struct conn_auth_cmd)))
return -EFAULT;
rtnl_lock();
write_lock_bh(&mode_lock);
if (track_mode == CONN_MODE_NONE && cmd.cmd == CONN_MODE_AUTH) {
track_mode = cmd.cmd;
conn_pid = cmd.pid;
conn_autologout = cmd.autologout;
memcpy(conn_auth_data, cmd.auth_data, CONN_AUTH_DATA_LEN);
hash_todo = 1; /* conn_hooks_init() */
} else if (track_mode == CONN_MODE_AUTH && cmd.cmd == CONN_MODE_NONE) {
track_mode = cmd.cmd;
conn_pid = 0;
conn_autologout = 0;
memset(conn_auth_data, 0, CONN_AUTH_DATA_LEN);
hash_todo = 2; /* conn_hooks_cleanup */
} else {
DEBUGP("Same Auth Cmd/n");
}
write_unlock_bh(&mode_lock);
if (hash_todo == 1) {
init_keepalive_timer();
conn_hooks_init();
printk(KERN_INFO "Drcom-Kernel: Authentication Started./n");
} else if (hash_todo == 2) {
del_keepalive_timer();
conn_hooks_cleanup();
conn_hash_cleanup();
printk(KERN_INFO "Drcom-Kernel: Authentication Stopped./n");
}
rtnl_unlock();
return 0;
}
static int conn_set_sockopt(struct sock *sk, int optname, void *optval, unsigned int optlen)
{
switch (optname) {
case CONN_SO_SET_PARAMS: /* set addresses of no need to auth */
return conn_set_params(sk, optname, optval, optlen);
case CONN_SO_SET_AUTH_CMD: /* set auth data, and start auth */
return conn_set_auth_cmd(sk, optname, optval, optlen);
default:
return -ENOPROTOOPT;
}
return -ENOPROTOOPT;
}
static struct nf_sockopt_ops conn_so_ops = {
.pf	     = PF_INET,
.set_optmin     = CONN_SO_BASE_CTL,
.set_optmax     = CONN_SO_SET_MAX+1,
.set	    = &conn_set_sockopt,
.owner	  = THIS_MODULE,
};
static int __init init(void)
{
int ret;
int i;
for (i=0; i<TCP_CONN_HASH_SIZE; i++)
INIT_LIST_HEAD(&tcp_conn_hash[i]);
ret = nf_register_sockopt(&conn_so_ops);
if(ret != 0)
return ret;
printk(KERN_INFO "Drcom-Kernel " TCPTRACK_VERSION " module loaded/n");
return ret;
}
static void __exit fini(void)
{
int do_dirty_work=0;
nf_unregister_sockopt(&conn_so_ops);
rtnl_lock();
write_lock_bh(&mode_lock);
if (track_mode == CONN_MODE_AUTH)
do_dirty_work = 1;
track_mode = CONN_MODE_NONE;
write_unlock_bh(&mode_lock);
if (do_dirty_work) {
conn_hooks_cleanup();
conn_hash_cleanup();
}
rtnl_unlock();
if (conn_e_addr)
kfree(conn_e_addr);
if (track_dev)
dev_put(track_dev);
printk(KERN_INFO "Drcom-Kernel " TCPTRACK_VERSION " module unloaded/n");
}
module_init(init);
module_exit(fini);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: