日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

ip 路由选项

發(fā)布時(shí)間:2024/3/24 78 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ip 路由选项 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
1.ip頭中選項(xiàng)格式 由于IP首部中可以存在選項(xiàng),且可以同時(shí)存在多個(gè)選項(xiàng),因此IP首部的長(zhǎng)度是可變的,IPv4允許選項(xiàng)最長(zhǎng)可達(dá)40字節(jié)。選項(xiàng)的格式有單字節(jié)和多字節(jié)兩種,單字節(jié)的即只包括一個(gè)字節(jié)的選項(xiàng)類型,而多字節(jié)的則除一個(gè)字節(jié)的類型之外,還包括選項(xiàng)長(zhǎng)度以及選項(xiàng)數(shù)據(jù)等。 多字節(jié)的選項(xiàng)格式如下所示: 所有選項(xiàng)都以1字節(jié)類型(type)字段開(kāi)始。在多字節(jié)選項(xiàng)中,類型字段后面緊接著一個(gè)長(zhǎng)度(len)字段,其他的字節(jié)是數(shù)據(jù)(data)。許多選項(xiàng)數(shù)據(jù)字段的第一個(gè)字節(jié)是1字節(jié)的位移(offset)字段,指向數(shù)據(jù)字段內(nèi)的某個(gè)字節(jié)。長(zhǎng)度字節(jié)的計(jì)算覆蓋了類型、長(zhǎng)度和數(shù)據(jù)字段。類型被繼續(xù)分成三個(gè)子字段: 1 bit 備份(copied )標(biāo)志、2 bit 類(class)字段和5 bit 數(shù)字(number)字段。
2.linux內(nèi)核存儲(chǔ)ip選項(xiàng)的結(jié)構(gòu)
  • struct ip_options {
  • ????__u32????????faddr;//存在寬松路由或嚴(yán)格路由選項(xiàng)時(shí),用來(lái)記錄嚇一跳的IP地址
  • ????unsigned char????optlen;//標(biāo)識(shí)IP首部中選項(xiàng)所占的字節(jié)數(shù)
  • ????unsigned char????srr;//記錄寬松路由或嚴(yán)格路由選項(xiàng)在IP首部中的偏移量,即選項(xiàng)的第一個(gè)字節(jié)的地址
  • ?????????????????????????? 減去IP首部的第一個(gè)字節(jié)的地址
  • ????unsigned char????rr;//用于記錄記錄路徑選項(xiàng)在IP首部中的偏移量
  • ????unsigned char????ts;
  • ????unsigned char????is_setbyuser:1,
  • ????????????is_data:1,
  • ????????????is_strictroute:1,
  • ????????????srr_is_hit:1,
  • ????????????is_changed:1,
  • ????????????rr_needaddr:1,
  • ????????????ts_needtime:1,
  • ????????????ts_needaddr:1;
  • ????unsigned char????router_alert;
  • ????unsigned char????cipso;
  • ????unsigned char????__pad2;
  • ????unsigned char????__data[0];//若選項(xiàng)有數(shù)據(jù)則從該字段開(kāi)始,使之緊跟在ip_options結(jié)構(gòu)后面,最多不
  • ???????????????????????????????? 超過(guò)40字節(jié)
  • };
  • 3.寬松路由選項(xiàng)(LSRR)和嚴(yán)格路由選項(xiàng)(SSRR)

    LSRR在選項(xiàng)的ip地址列表中并不列出一條完備而嚴(yán)格的路徑,而是只給出路徑中的某些關(guān)鍵點(diǎn)。在關(guān)鍵的之間可以通過(guò)路由器的自動(dòng)路由選擇功能進(jìn)行路由,此選項(xiàng)在數(shù)據(jù)包分片的時(shí)候也必須被復(fù)制。

    SSRR選項(xiàng)要求數(shù)據(jù)包必須嚴(yán)格按照發(fā)送方規(guī)定的路徑經(jīng)過(guò)每一個(gè)路由器,這些路由器應(yīng)該是一一相連的,每?jī)蓚€(gè)指定的路由器之間不能有其他未指定的路由器,且路由器的順序是不能改變的。如果數(shù)據(jù)包在傳輸時(shí)無(wú)法直接到達(dá)下一跳指定的路由器,路由器就會(huì)丟棄該數(shù)據(jù)包,然后產(chǎn)生一個(gè)源路由失敗的目的不可達(dá)的ICMP差錯(cuò)報(bào)文報(bào)告給發(fā)送方。

    內(nèi)核定義的ip選項(xiàng)類型值:

  • /* IP options */
  • #define IPOPT_COPY????????0x80
  • #define IPOPT_CLASS_MASK????0x60
  • #define IPOPT_NUMBER_MASK????0x1f

  • #define????IPOPT_COPIED(o)????????((o)&IPOPT_COPY)
  • #define????IPOPT_CLASS(o)????????((o)&IPOPT_CLASS_MASK)
  • #define????IPOPT_NUMBER(o)????????((o)&IPOPT_NUMBER_MASK)

  • #define????IPOPT_CONTROL????????0x00
  • #define????IPOPT_RESERVED1????????0x20
  • #define????IPOPT_MEASUREMENT????0x40
  • #define????IPOPT_RESERVED2????????0x60

  • #define IPOPT_END????(0 |IPOPT_CONTROL)
  • #define IPOPT_NOOP????(1 |IPOPT_CONTROL)
  • #define IPOPT_SEC????(2 |IPOPT_CONTROL|IPOPT_COPY)
  • #define IPOPT_LSRR????(3 |IPOPT_CONTROL|IPOPT_COPY)//寬松路由的type值,即0x83
  • #define IPOPT_TIMESTAMP????(4 |IPOPT_MEASUREMENT)
  • #define IPOPT_CIPSO????(6 |IPOPT_CONTROL|IPOPT_COPY)
  • #define IPOPT_RR????(7 |IPOPT_CONTROL)
  • #define IPOPT_SID????(8 |IPOPT_CONTROL|IPOPT_COPY)
  • #define IPOPT_SSRR????(9 |IPOPT_CONTROL|IPOPT_COPY)//嚴(yán)格路由的type值,即0x89
  • #define IPOPT_RA????(20|IPOPT_CONTROL|IPOPT_COPY)
  • 4.分析一個(gè)完整的ip選項(xiàng)處理流程(從setsockopt設(shè)置選項(xiàng)到發(fā)送syn、路由節(jié)點(diǎn)接收syn到轉(zhuǎn)發(fā)syn及目的端接收syn到發(fā)送synack的ip選項(xiàng)的處理過(guò)程)

    (1)從setsockopt設(shè)置選項(xiàng)到發(fā)送syn

    用戶層socket編程可以通過(guò)setsockopt來(lái)設(shè)置ip選項(xiàng),在connect前設(shè)置選項(xiàng)值

  • setsockopt(sockfd,IPPROTO_IP,IP_OPTIONS,(void*)opt,optlen);
  • setsockopt系統(tǒng)調(diào)用在內(nèi)核中的實(shí)現(xiàn),之前已經(jīng)介紹過(guò)了。現(xiàn)在我們直接跳到函數(shù)
  • int ip_setsockopt(struct sock *sk, int level,
  • ????????int optname, char __user *optval, int optlen)
  • {
  • ??? ......
  • ????err = do_ip_setsockopt(sk, level, optname, optval, optlen);//IPPPROTO_IP的處理函數(shù)
  • ??? ......
  • }
  • static int do_ip_setsockopt(struct sock *sk, int level,
  • ????????int optname, char __user *optval, int optlen)
  • {
  • ????struct inet_sock *inet = inet_sk(sk);
  • ??? ......
  • ????lock_sock(sk);

  • ????switch (optname) {
  • ????????case IP_OPTIONS://ip_options選項(xiàng)處理
  • ????????{
  • ????????????struct ip_options * opt = NULL;
  • ????????????if (optlen > 40 || optlen < 0)
  • ????????????????goto e_inval;
  • ????????????err = ip_options_get_from_user(&opt, optval, optlen);
  • ????????????if (err)
  • ????????????????break;
  • ????????????if (inet->is_icsk) {
  • ????????????????struct inet_connection_sock *icsk = inet_csk(sk);
  • ????????????????......
  • ????????????????????if (inet->opt)
  • ????????????????????????icsk->icsk_ext_hdr_len -= inet->opt->optlen;
  • ????????????????????if (opt)
  • ????????????????????????icsk->icsk_ext_hdr_len += opt->optlen;
  • ????????????????????icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
  • ??????????????? ......
  • ????????????}
  • ????????????opt = xchg(&inet->opt, opt);//將opt與inet->opt交換;現(xiàn)在inet->opt中存儲(chǔ)了我們解
  • ????????????????????????????????????????? 析過(guò)的選項(xiàng)的值,inet->opt->faddr為下一跳的地址
  • ????????????kfree(opt);
  • ????????????break;
  • ????????}
  • ????????......
  • }
  • int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen)
  • {
  • ????struct ip_options *opt = ip_options_get_alloc(optlen);

  • ????if (!opt)
  • ????????return -ENOMEM;
  • ????if (optlen && copy_from_user(opt->__data, data, optlen)) {//?應(yīng)用層數(shù)據(jù)拷貝到opt->__da
  • ???????????????????????????????????????????????????????????????? ta指向的內(nèi)存處
  • ????????kfree(opt);
  • ????????return -EFAULT;
  • ????}
  • ????return ip_options_get_finish(optp, opt, optlen);//解析opt信息并用optp返回
  • }
  • static int ip_options_get_finish(struct ip_options **optp,
  • ???????????????? struct ip_options *opt, int optlen)
  • {
  • ????while (optlen & 3)
  • ????????opt->__data[optlen++] = IPOPT_END;//如IP選項(xiàng)內(nèi)容不是以四字節(jié)對(duì)齊的,則將未對(duì)齊部分用選
  • ??????????????????????????????????????????? 項(xiàng)列表結(jié)束符填充,使之對(duì)齊
  • ????opt->optlen = optlen;
  • ????opt->is_data = 1;
  • ????opt->is_setbyuser = 1;
  • ????if (optlen && ip_options_compile(opt, NULL)) {//解析IP選項(xiàng)信息塊各字段值
  • ????????kfree(opt);
  • ????????return -EINVAL;
  • ????}
  • ????kfree(*optp);
  • ????*optp = opt;
  • ????return 0;
  • }
  • int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
  • {
  • ??????? ......
  • ????????switch (*optptr) {
  • ???????? case IPOPT_SSRR:
  • ???????? case IPOPT_LSRR:
  • ????????????if (optlen < 3) {//1字節(jié)type,1字節(jié)len,1字節(jié)offset
  • ????????????????pp_ptr = optptr + 1;
  • ????????????????goto error;
  • ????????????}
  • ????????????if (optptr[2] < 4) {//offset至少為4,指向第一個(gè)ip
  • ????????????????pp_ptr = optptr + 2;
  • ????????????????goto error;
  • ????????????}
  • ????????????/* NB: cf RFC-1812 5.2.4.1 */
  • ????????????if (opt->srr) {
  • ????????????????pp_ptr = optptr;
  • ????????????????goto error;
  • ????????????}
  • ????????????if (!skb) {
  • ????????????????if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {//至少能容下一個(gè)ip
  • ????????????????????pp_ptr = optptr + 1;
  • ????????????????????goto error;
  • ????????????????}
  • ????????????????memcpy(&opt->faddr, &optptr[3], 4);//取出第一個(gè)地址作為下一跳地址,
  • ???????????????????????????????????????????????????? opt->faddr為下一跳的地址
  • ????????????????if (optlen > 7)
  • ????????????????????memmove(&optptr[3], &optptr[7], optlen-7);//在路徑列表中多于一個(gè)地址
  • ???????????????????????????????????????????????????????時(shí),將剩余的所有地址往前移動(dòng)4個(gè)字節(jié)
  • ????????????}
  • ????????????opt->is_strictroute = (optptr[0] == IPOPT_SSRR);//記錄是否為嚴(yán)格路由選項(xiàng)
  • ????????????opt->srr = optptr - iph;//記錄源路由選項(xiàng)在IP首部的偏移量
  • ????????????break;
  • ??????????? ......
  • }
  • options的offset項(xiàng)沒(méi)有修改,它指向了源地址路由的下一個(gè)節(jié)點(diǎn),因?yàn)榇藭r(shí)第一個(gè)路由節(jié)點(diǎn)已經(jīng)從選項(xiàng)中刪除,其他路由節(jié)點(diǎn)向前移動(dòng)了4個(gè)字節(jié)
  • 應(yīng)用層socket編程connect函數(shù)將執(zhí)行系統(tǒng)調(diào)用sys_connect

  • asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
  • {
  • ????struct socket *sock;
  • ??? ......
  • ????err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
  • ???????????????? sock->file->f_flags);
  • ????......
  • }
  • sock->ops指向注冊(cè)的proto_ops鉤子,此時(shí)為tcp_prot
  • struct proto tcp_prot = {
  • ????.name????????????= "TCP",
  • ??? ......
  • ????.connect????????= tcp_v4_connect,
  • ????......
  • };
  • int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
  • {
  • ????struct inet_sock *inet = inet_sk(sk);
  • ????struct tcp_sock *tp = tcp_sk(sk);
  • ????struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
  • ??? ......

  • ????nexthop = daddr = usin->sin_addr.s_addr;
  • ????if (inet->opt && inet->opt->srr) {//將臨時(shí)變量下一跳地址和目的地址值都暫時(shí)設(shè)置為connect參
  • ?????????????????????????? ?數(shù)中的地址,如果使用源地址路由,則將下一跳地址設(shè)置為IP選項(xiàng)中的faddr
  • ????????if (!daddr)
  • ????????????return -EINVAL;
  • ????????nexthop = inet->opt->faddr;
  • ????}

  • ????tmp = ip_route_connect(&rt, nexthop, inet->saddr,//查找路由緩存項(xiàng)
  • ???????????? RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
  • ???????????? IPPROTO_TCP,
  • ???????????? inet->sport, usin->sin_port, sk, 1);//
  • ????if (tmp < 0) {
  • ????????if (tmp == -ENETUNREACH)
  • ????????????IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
  • ????????return tmp;
  • ????}
  • ??? ......
  • ????err = tcp_connect(sk);//發(fā)送syn包
  • ????rt = NULL;
  • ????if (err)
  • ????????goto failure;
  • ??? ......
  • }
  • int tcp_connect(struct sock *sk)
  • {
  • ??? ......
  • ????buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation);//分配skbuff
  • ??? ......
  • ????tcp_transmit_skb(sk, buff, 1, GFP_KERNEL);//構(gòu)造tcp頭和ip頭并發(fā)送
  • ????......
  • }
  • static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, gfp_t gfp_mask)
  • {
  • ??? ......
  • ????err = icsk->icsk_af_ops->queue_xmit(skb, 0);//構(gòu)造ip頭并發(fā)送,queue_xmit注冊(cè)為
  • ????????????????????????????????????????????????? ip_queue_xmit函數(shù)
  • ??? ......
  • }
  • struct inet_connection_sock_af_ops ipv4_specific = {
  • ????.queue_xmit???? = ip_queue_xmit,
  • ??? ......
  • };
  • int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
  • {
  • ????struct sock *sk = skb->sk;
  • ????struct inet_sock *inet = inet_sk(sk);
  • ????struct ip_options *opt = inet->opt;
  • ????struct rtable *rt;
  • ????struct iphdr *iph;
  • ??? ......

  • ????????/* Use correct destination address if we have options. */
  • ????????daddr = inet->daddr;
  • ????????if(opt && opt->srr)//如果使用源地址路由,下一跳為inet->opt->faddr,即選項(xiàng)中的第一個(gè)地址
  • ????????????daddr = opt->faddr;

  • ????????{
  • ????????????struct flowi fl = { .oif = sk->sk_bound_dev_if,
  • ???????????????????? .nl_u = { .ip4_u =
  • ???????????????????????? { .daddr = daddr,
  • ????????????????????????????.saddr = inet->saddr,
  • ????????????????????????????.tos = RT_CONN_FLAGS(sk) } },
  • ???????????????????? .proto = sk->sk_protocol,
  • ???????????????????? .uli_u = { .ports =
  • ???????????????????????? { .sport = inet->sport,
  • ???????????????????????????? .dport = inet->dport } } };

  • ????????????/* If this fails, retransmit mechanism of transport layer will
  • ???????????? * keep trying until route appears or the connection times
  • ???????????? * itself out.
  • ???????????? */
  • ????????????security_sk_classify_flow(sk, &fl);
  • ????????????if (ip_route_output_flow(&rt, &fl, sk, 0))
  • ????????????????goto no_route;
  • ????????}
  • ????????sk_setup_caps(sk, &rt->u.dst);
  • ????}
  • ????skb->dst = dst_clone(&rt->u.dst);

  • packet_routed:
  • ????if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)//如果是嚴(yán)格路由選項(xiàng),并且網(wǎng)關(guān)地址和路由的下一跳不一致則中斷處理流程,這也是嚴(yán)格路由所要求的:下一跳必須是選項(xiàng)中的順序的地址
  • ????????goto no_route;
  • ??? ......
  • ????iph->saddr = rt->rt_src;
  • ????iph->daddr = rt->rt_dst;//目的地址已經(jīng)是路由的下一跳地址,即為選項(xiàng)中的第一個(gè)地址,即為
  • ??????????????????????????????inet->opt->faddr
  • ????skb->nh.iph = iph;
  • ????/* Transport layer set skb->h.foo itself. */

  • ????if (opt && opt->optlen) {
  • ????????iph->ihl += opt->optlen >> 2;
  • ????????ip_options_build(skb, opt, inet->daddr, rt, 0);//將目的地址到options中最后一個(gè)ip地
  • ???????????????????????????????????????????????????????? 址后面
  • ????}
  • ??? ......
  • }
  • 發(fā)送syn的處理告一段落,將通過(guò)一個(gè)實(shí)例來(lái)體現(xiàn)這一流程:

    實(shí)驗(yàn)一(LSRR):

    客戶端:192.168.18.73 路由節(jié)點(diǎn)1:192.168.18.71 路由節(jié)點(diǎn)2:192.168.18.72 服務(wù)器端:192.168.18.76 18.71上18.0網(wǎng)段有個(gè)網(wǎng)關(guān)192.168.18.79

    18.73抓包(發(fā)送syn包)結(jié)果如下:

    一個(gè)NOP是為了對(duì)齊而設(shè)置的。從圖中可以看出目的地址改為了options中首個(gè)ip地址,偏移量指向了下一個(gè)路由節(jié)點(diǎn)地址,絕對(duì)目的地址被加入了options末尾。len為1個(gè)字節(jié)的type+1個(gè)字節(jié)len+1個(gè)字節(jié)的offset+2個(gè)四個(gè)字節(jié)的ip地址

    如果在73上設(shè)定網(wǎng)關(guān)18.79后,syn包發(fā)送不受影響

    實(shí)驗(yàn)二(SSRR):

    如果設(shè)定18.79網(wǎng)關(guān),syn包就發(fā)不出去了,原因在ip_queue_xmit函數(shù)中分析過(guò)了

    總結(jié)

    以上是生活随笔為你收集整理的ip 路由选项的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。