免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

Linux下如何實現(xiàn)網(wǎng)絡(luò)狀態(tài)檢測

 白雪~~~ 2012-02-25

. iptables規(guī)則中的state匹配
在2.4/2.6內(nèi)核的Linux中的防火墻代碼netfilter中實現(xiàn)了狀態(tài)檢測(stateful inspection)檢測技術(shù),在命令行接口的iptables命令是通過匹配“-m state”來實現(xiàn),“-m state”匹配中定義了四種狀態(tài):
NEW,表示新連接;
ESTABLISHED,表示已經(jīng)建立的連接;
RELATED,表示相關(guān)的子連接;
INVALID,表示非法狀態(tài)。
所以在制定iptables規(guī)則時,只需要定義單向的規(guī)則,再加上如下兩條規(guī)則,就可以保證連接回應(yīng)包能正確通過防火墻而不必加反向規(guī)則:
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD -m state --state INVALID -j DROP
(如果是保護本機,將FORWARD改為INPUT)
2. 內(nèi)核中的state匹配的實現(xiàn)
(以下的內(nèi)核代碼基于2.4.26內(nèi)核)
和匹配state對應(yīng)的內(nèi)核部分實現(xiàn)是ipt_state.c(net/ipv4/netfilter),匹配部分的代碼非常簡單,就是根據(jù)函數(shù)ip_conntrack_get()的返回值來判斷數(shù)據(jù)包的狀態(tài)類型:

if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
statebit = IPT_STATE_INVALID;
else
statebit = IPT_STATE_BIT(ctinfo);

3. skb與ip_conntrack的關(guān)聯(lián)
再跟蹤到ip_conntrack_get()函數(shù) (net/ipv4/netfilter_ipv4/ip_conntrack_core.c),該函數(shù)有兩個參數(shù),一個是指向sk_buff數(shù)據(jù)包的指 針skb,另一個是枚舉類型enum ip_conntrack_info的指針,
實際上是一個返回參數(shù),將返回數(shù)據(jù)包的狀態(tài)類型;該函數(shù)的返回值是連接結(jié)構(gòu)struct ip_conntrack的指針,表示該包屬于哪個連接,如果連接不存在,返回空,該包也將被認為是非法包:
struct ip_conntrack *
ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
{
if (skb->nfct)
return __ip_conntrack_get(skb->nfct, ctinfo);
return NULL;
}
ip_conntrack_get()函數(shù)本身也很簡單,實際上是__ip_conntrack_get()函數(shù) (net/ipv4/netfilter_ipv4/ip_conntrack_core.c)的包裹函數(shù),判斷skb的nfct是否非空,非空則將其和 枚舉指針ctinfo傳給__ip_conntrack_get()函數(shù),nfct是sk_buff中用于描述netfilter conntrack信息的struct nf_ct_info指針,在內(nèi)核配置了CONFIG_NETFILTER后有效。struct nf_ct_info結(jié)構(gòu)在include/linux/sk_buff.h中定義:

struct nf_conntrack {
atomic_t use;
void (*destroy)(struct nf_conntrack *);
};
struct nf_ct_info {
struct nf_conntrack *master;
};

在__ip_conntrack_get()函數(shù)中,通過nfct->master獲取連接指針ct,而nfct相對于ct成員infos的偏移就是連接狀態(tài):
static inline struct ip_conntrack *
__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack *ct
= (struct ip_conntrack *)nfct->master;
/* ctinfo is the index of the nfct inside the conntrack */
*ctinfo = nfct - ct->infos;
IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
return ct;
}
由此可見,netfilter的狀態(tài)檢測過程很簡潔,如果skb包中的nfct指針設(shè)置了的話,可以很快地確定該skb包屬于哪個連接,如果不屬于任何連接則是非法包。現(xiàn)在的焦點是skb中的nfct值是如何設(shè)置的?

4. netfilter如何實現(xiàn)中skb與ip_conntrack連接的關(guān)聯(lián)
nfct值是在resolve_normal_ct()函數(shù)(net/ipv4/netfilter/ip_conntrack_core.c)中定義的,該函
數(shù)被ip_conntrack_in()函數(shù)(net/ipv4/netfilter/ip_conntrack_core.c)調(diào)用,在 ip_conntrack_local()函數(shù)(net/ipv4/netfilter/ip_conntrack_standalone.c)中調(diào)用了
ip_conntrack_in()函數(shù),而這兩個函數(shù)分別是PREROUTING鏈和OUTPUT鏈的起始函數(shù),由下面兩個結(jié)構(gòu)
定義(net/ipv4/netfilter/ip_conntrack_standalone.c):
static struct nf_hook_ops ip_conntrack_in_ops
= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,
NF_IP_PRI_CONNTRACK };
static struct nf_hook_ops ip_conntrack_local_out_ops
= { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,
NF_IP_PRI_CONNTRACK };

這說明netfilter是在連接的第一個包時就建立連接了,這個連接可能是由外部發(fā)起的,也可能是由本機發(fā)起的,后續(xù)包查找連接HASH表找到相應(yīng)的連接,然后賦值給skb結(jié)構(gòu)中的nfct,這就是resolve_normal_ct()函數(shù)的工作:
/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
static inline struct ip_conntrack *
resolve_normal_ct(struct sk_buff *skb, // 數(shù)據(jù)包
struct ip_conntrack_protocol *proto, // 連接協(xié)議跟蹤,該結(jié)構(gòu)對應(yīng)協(xié)議特殊處理過程,如TCP的狀態(tài)轉(zhuǎn)換等
int *set_reply, // 返回值,表示該包是否是響應(yīng)方的包
unsigned int hooknum,
enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack_tuple tuple;
struct ip_conntrack_tuple_hash *h;
IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
// 確定該包對應(yīng)的tuple,對TCP/UDP協(xié)議來說就是地址協(xié)議端口的5元組
if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
return NULL;
/* look for tuple match */
// 根據(jù)tuple值查找連接HASH
h = ip_conntrack_find_get(&tuple, NULL);
if (!h) {
// 在當前連接表中沒找到,說明是新連接的包,初始化新連接
h = init_conntrack(&tuple, proto, skb);
if (!h)
return NULL;
// 該包非法返回NULL,其他錯誤會返回錯誤號的負值
if (IS_ERR(h))
return (void *)h;
}
/* It exists; we have (non-exclusive) reference. */
if (DIRECTION(h) == IP_CT_DIR_REPLY) {
// 連接回應(yīng)方向包
*ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
/* Please set reply bit if this packet OK */
// 這個包是響應(yīng)方的包
*set_reply = 1;
} else {
// 連接原始方向的包
/* Once we've had two way comms, always ESTABLISHED. */
if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
DEBUGP("ip_conntrack_in: normal packet for %p\n",
h->ctrack);
// 如果不是第一個包,設(shè)置ESTABLISHED屬性,這個位標志表示發(fā)現(xiàn)了響應(yīng)方發(fā)的包,
// 表示連接可以建立,該標志在ip_conntrack_in()函數(shù)中設(shè)置
*ctinfo = IP_CT_ESTABLISHED;
} else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
DEBUGP("ip_conntrack_in: related packet for %p\n",
h->ctrack);
// 該標志表示是子連接的包,如FTP的數(shù)據(jù)連接
// 該標志在init_conntrack()函數(shù)中設(shè)置
*ctinfo = IP_CT_RELATED;
} else {
DEBUGP("ip_conntrack_in: new packet for %p\n",
h->ctrack);
// 沒有任何標志,是連接的第一個包,設(shè)置為NEW屬性
*ctinfo = IP_CT_NEW;
}
// 這個包是發(fā)起方的包
*set_reply = 0;
}
// infos是數(shù)量為IP_CT_NUMBER(=5)的數(shù)組,分別對應(yīng)連接發(fā)起方向的
// NEW(2)/ESTABLISHED(0)/RELATED(1)
// 和連接響應(yīng)方向的ESTABLISHED(3)/RELATED(4)
// 每個skb包都會劃歸為其中一類, 也就是ctinfo的值
// 每個skb包根據(jù)其類型,將其nfct值設(shè)為相應(yīng)infos項的地址
skb->nfct = &h->ctrack->infos[*ctinfo];
return h->ctrack;
}
在init_conntrack()函數(shù)中將連接的infos值初始化為:
...
for (i=0; i < IP_CT_NUMBER; i++)
conntrack->infos[i].master = &conntrack->ct_general;
...
也就是infos各項的值都是相同的,沒有發(fā)現(xiàn)在其他地方重新賦值,所以把所有項實際都是相同的,指向同一個連接。設(shè)計之初可能是考慮要區(qū)分, 但實現(xiàn)時還是只用到一個就行了,在其他地方基本只用到infos[0]進行處理,infos的用處目前只用來判斷狀態(tài),也就是每一項相對于infos [0]的偏移值。
最后討論一下為什么在__ip_conntrack_get()函數(shù)中nfct->master值就是連接的地址:
__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack *ct
= (struct ip_conntrack *)nfct->master;
...
skb的nfct值是infos數(shù)組中某一項的地址,而這些項中的master成員都初始化為連接中ct_general的地址,而ct_general參數(shù)是連接結(jié)構(gòu)的第一項參數(shù),所以其地址和連接結(jié)構(gòu)的地址是相同,在Linux內(nèi)核中,類似用法很多。
5. 結(jié)論
在每個skb數(shù)據(jù)包進入netfilter架構(gòu)時,netfilter就會給其建立連接,通過簡單方法就能找到連接,能區(qū)分出發(fā)起方、響應(yīng)方以及第一個包還是后續(xù)包,并能識別子連接,從而實現(xiàn)狀態(tài)檢測。
連接結(jié)構(gòu)中的infos數(shù)組就目前而言似乎不是很必要,單值就可以,然后增加一個連接狀態(tài)參數(shù),而不是通過infos的偏移來判斷。




// Linux下檢測網(wǎng)絡(luò)狀態(tài)是否正常 
 
#include <sys/types.h> 
#include <string.h> 
#include <stdlib.h> 
#include <sys/ioctl.h> 
#include <stdio.h> 
#include <errno.h> 
#include <net/if.h> 
 
 
struct ethtool_value { 
        __uint32_t      cmd; 
        __uint32_t      data; 
}; 
 
 
int main(int argc, char* argv[]) 

    struct ethtool_value edata; 
    int fd = -1, err = 0; 
    struct ifreq ifr; 
 
 
        memset(&ifr, 0, sizeof(ifr)); 
        strcpy(ifr.ifr_name, "eth0"); 
        fd = socket(AF_INET, SOCK_DGRAM, 0); 
        if (fd < 0) { 
                perror("Cannot get control socket"); 
                return 70; 
        } 
 
 
        edata.cmd = 0x0000000a; 
        ifr.ifr_data = (caddr_t)&edata; 
        err = ioctl(fd, 0x8946, &ifr); 
        if (err == 0) { 
                fprintf(stdout, "Link detected: %s/n", 
                        edata.data ? "yes":"no"); 
        } else if (errno != EOPNOTSUPP) { 
                perror("Cannot get link status"); 
        } 
   return 0; 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多