ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

         
     
    Реалізація мережі в операційній системі Linux
         

     

    Інформатика, програмування

    Реалізація мережі в операційній системі Linux

    Гліб Пахаренко

    Розглянемо докладніше що відбувається з пакетом при попаданні в нашу машину. Спочатку він обробляється драйвером апаратури (мережевої карти і т.д) якщо пакет призначений нам то він посилається на вище лежить рівень - мережевий там визначається для кого він призначений: нам або комусь іншому, для цього проглядається кеш маршрутизації, якщо там немає маршруту то Forwarding Information Base (FIB), якщо пакет призначений іншого комп'ютера те ядро шле його на відповідний пристрій (мережеву карту), якщо нам, то через транспортний і вищерозміщені рівні з додатком. Обмін даними між додатком і ядром здійснюється через абстракцію сокета. У Линух використовується BSD сокет.

    Розглянемо детальніше структуру пакета

    Ключ до швидкого обміну даними у використанні структури sk_buf і передачі на вищі рівні тільки вказівника на неї

    опис структури лежить в linux/skbuff.h

    її поля

    struct sk_buff (

    /* These two members must be first. */

    struct sk_buff * next;/* Next buffer in list */

    struct sk_buff * prev;/* Previous buffer in list */

    struct sk_buff_head * list;/* List we are on */

    struct sock * sk;/* Socket we are owned by */

    struct timeval stamp;/* Time we arrived */

    struct net_device * dev;/* Device we arrived on/are leaving by */

    /* Transport layer header */

    union

    (

    struct tcphdr * th;

    struct udphdr * uh;

    struct icmphdr * icmph;

    struct igmphdr * igmph;

    struct iphdr * ipiph;

    struct spxhdr * spxh;

    unsigned char * raw;

    ) h;

    /* Network layer header */

    union

    (

    struct iphdr * iph;

    struct ipv6hdr * ipv6h;

    struct arphdr * arph;

    struct ipxhdr * ipxh;

    unsigned char * raw;

    ) nh;

    /* Link layer header */

    union

    (

    struct ethhdr * ethernet;

    unsigned char * raw;

    ) mac;

    struct dst_entry * dst;

    /*

    * This is the control buffer. It is free to use for every

    * layer. Please put your private variables there. If you

    * want to keep them across layers you have to do a skb_clone ()

    * first. This is owned by whoever has the skb queued ATM.

    */

    char cb [48];

    unsigned int len;/* Length of actual data */

    unsigned int data_len;

    unsigned int csum;/* Checksum */

    unsigned char __unused,/* Dead field, may be reused */

    cloned,/* head may be cloned (check refcnt to be sure). */

    pkt_type,/* Packet class */

    ip_summed;/* Driver fed us an IP checksum */

    __u32 priority;/* Packet queueing priority */

    atomic_t users;/* User count - see datagram.c, tcp.c */

    unsigned short protocol;/* Packet protocol from driver. */

    unsigned short security;/* Security level of packet */

    unsigned int truesize;/* Buffer size */

    unsigned char * head;/* Head of buffer */

    unsigned char * data;/* Data head pointer */

    unsigned char * tail;/* Tail pointer */

    unsigned char * end;/* End pointer */

    void (* destructor) (struct sk_buff *);/* Destruct function */

    # ifdef CONFIG_NETFILTER

    /* Can be used for communication between hooks. */

    unsigned long nfmark;

    /* Cache info */

    __u32 nfcache;

    /* Associated connection, if any */

    struct nf_ct_info * nfct;

    # ifdef CONFIG_NETFILTER_DEBUG

    unsigned int nf_debug;

    # endif

    # endif/* CONFIG_NETFILTER */

    # if defined (CONFIG_HIPPI)

    union (

    __u32 ifield;

    ) private;

    # endif

    # ifdef CONFIG_NET_SCHED

    __u32 tc_index;/* traffic control index */

    # endif

    );

    там ж міститься маса корисних функцій для роботи з sk_buff. всі протоколи використовують ету структуру додаючи заголовки свого рівня

    Маршрутизація

    Рівень IP використовує 3 структури для маршрутизації FIB де зберігаються всі маршрути routing cache де знаходяться найбільш часто використовувані neibour table список комп'ютерів фізично з'єднаних з даними

    FIB містить 32 зони по одній на кожен біт ip адреси кожна зона містить точки входу для хостів та мереж які задайтся даної маскою підмережі 255.0.0.0 має 8 значущих біт і тому у восьмий зоні 255.255.255.0 в 24 зоні

    файл/proc/net/route містить FIB

    routing cache хеш-таблиця то він додається туди з FIB застарілі записи після закінчення деякого часу видаляються вміст кеша можна побачити в/proc/net/rt_cache

    Ініціалізація мережі

    головні налаштування мережі в дистрибутиві RedHat (Mandrake) лежать в/etc/sysconfig/network,/etc/sysconfig/network-scripts/ifcfg-eth0 і тд ...

    вміст моїх файлів (не в virtual mashine редхате а на нормальній машині Mandrake-8.2 де відповідно немає ніяких мережевих карт)

    /etc/sysconfig/network

    NETWORKING = yes

    FORWARD_IPV4 = false

    HOSTNAME = freeland.linux

    DOMAINNAME = linux

    /etc/sysconfig/network-scripts/ifcfg-lo

    DEVICE = lo

    IPADDR = 127.0.0.1

    NETMASK = 255.0.0.0

    NETWORK = 127.0.0.0

    # If you're having problems with gated making 127.0.0.0/8 a martian,

    # you can change this to something else (255.255.255.255, for example)

    BROADCAST = 127.255.255.255

    ONBOOT = yes

    NAME = loopback

    Дуже корисної програмою є ifconfig синтаксис якій детально розглянуто в мануалі

    [20:16] [pts1]/etc/sysconfig/network-scripts [root]

    # ifconfig

    lo Link encap: Local Loopback

    inet addr: 127.0.0.1 Mask: 255.0.0.0

    UP LOOPBACK RUNNING MTU: 16436 Metric: 1

    RX packets: 3242 errors: 0 dropped: 0 overruns: 0 frame: 0

    TX packets: 3242 errors: 0 dropped: 0 overruns: 0 carrier: 0

    collisions: 0 txqueuelen: 0

    RX bytes: 227644 (222.3 Kb) TX bytes: 227644 (222.3 Kb)

    НЕ менш корисна команда route

    # route

    Kernel IP routing table

    Destination Gateway Genmask Flags Metric Ref Use Iface

    127.0.0.0 * 255.0.0.0 U 0 0 0 lo

    її призначення, а також багатьох інших описано в Linux Network Administrator Guide

    З'єднання

    В цій частині ми детально розглянемо сокета і все що з ними пов'язано

    Коли процес створює сокет то він порожній потім система визначає маршрут до віддаленого хосту і вносить цю інформацію в сокет. Після цього пакети направляються на потрібне пристрій

    Є два типи сокетов BSD сокети які включають як член INET cокети BSD сокети описуються структурою struct socket в linux/net.h

    struct socket

    (

    socket_state state;

    unsigned long flags;

    struct proto_ops * ops;

    struct inode * inode;

    struct fasync_struct * fasync_list; / * Asynchronous wake up list */

    struct file * file;/* File back pointer for gc */

    struct sock * sk;

    wait_queue_head_t wait;

    short type;

    unsigned char passcred;

    );

    struct proto_ops (

    int family;

    int (* release) (struct socket * sock);

    int (* bind) (struct socket * sock, struct sockaddr * umyaddr,

    int sockaddr_len);

    int (* connect) (struct socket * sock, struct sockaddr * uservaddr,

    int sockaddr_len, int flags);

    int (* socketpair) (struct socket * sock1, struct socket * sock2);

    int (* accept) (struct socket * sock, struct socket * newsock,

    int flags);

    int (* getname) (struct socket * sock, struct sockaddr * uaddr,

    int * usockaddr_len, int peer);

    unsigned int (* poll) (struct file * file, struct socket * sock, struct poll_table_struct * wait);

    int (* ioctl) (struct socket * sock, unsigned int cmd,

    unsigned long arg);

    int (* listen) (struct socket * sock, int len);

    int (* shutdown) (struct socket * sock, int flags);

    int (* setsockopt) (struct socket * sock, int level, int optname,

    char * optval, int optlen);

    int (* getsockopt) (struct socket * sock, int level, int optname,

    char * optval, int * optlen);

    int (* sendmsg) (struct socket * sock, struct msghdr * m, int total_len, struct scm_cookie * scm);

    int (* recvmsg) (struct socket * sock, struct msghdr * m, int total_len, int flags, struct scm_cookie * scm);

    int (* mmap) (struct file * file, struct socket * sock, struct vm_area_struct * vma);

    ssize_t (* sendpage) (struct socket * sock, struct page * page, int offset, size_t size, int flags);

    );

    найбільш важливі поля

    * struct proto_ops * ops вказує на протокольно залежні функції

    struct inode на inode файлу сокета

    struct sock * на инет сокет

    INET net/sock.h struct sock

    struct sock (

    /* Socket demultiplex comparisons on incoming packets. */

    __u32 daddr;/* Foreign IPv4 addr */

    __u32 rcv_saddr;/* Bound local IPv4 addr */

    __u16 dport;/* Destination port */

    unsigned short num;/* Local port */

    int bound_dev_if;/* Bound device index if! = 0 */

    /* Main hash linkage for various protocol lookup tables. */

    struct sock * next;

    struct sock ** pprev;

    struct sock * bind_next;

    struct sock ** bind_pprev;

    volatile unsigned char state,/* Connection state */

    zapped;/* In ax25 & ipx means not linked */

    __u16 sport;/* Source port */

    unsigned short family;/* Address family */

    unsigned char reuse;/* SO_REUSEADDR setting */

    unsigned char shutdown;

    atomic_t refcnt;/* Reference count */

    socket_lock_t lock;/* Synchronizer ... */

    int rcvbuf;/* Size of receive buffer in bytes */

    wait_queue_head_t * sleep;/* Sock wait queue */

    struct dst_entry * dst_cache;/* Destination cache */

    rwlock_t dst_lock;

    atomic_t rmem_alloc;/* Receive queue bytes committed */

    struct sk_buff_head receive_queue; / * Incoming packets */

    atomic_t wmem_alloc;/* Transmit queue bytes committed */

    struct sk_buff_head write_queue;/* Packet sending queue */

    atomic_t omem_alloc;/* "o" is "option" or "other" */

    int wmem_queued;/* Persistent queue size */

    int forward_alloc;/* Space allocated forward. */

    __u32 saddr;/* Sending source */

    unsigned int allocation;/* Allocation mode */

    int sndbuf;/* Size of send buffer in bytes */

    struct sock * prev;

    /* Not all are volatile, but some are, so we might as well say they all are.

    * XXX Make this a flag word-DaveM

    */

    volatile char dead,

    done,

    urginline,

    keepopen,

    linger,

    destroy,

    no_check,

    broadcast,

    bsdism;

    unsigned char debug;

    unsigned char rcvtstamp;

    unsigned char use_write_queue;

    unsigned char userlocks;

    /* Hole of 3 bytes. Try to pack. */

    int route_caps;

    int proc;

    unsigned long lingertime;

    int hashent;

    struct sock * pair;

    /* The backlog queue is special, it is always used with

    * the per-socket spinlock held and requires low latency

    * access. Therefore we special case it's implementation.

    */

    struct (

    struct sk_buff * head;

    struct sk_buff * tail;

    ) backlog;

    rwlock_t callback_lock;

    /* Error queue, rarely used. */

    struct sk_buff_head error_queue;

    struct proto * prot;

    # if defined (CONFIG_IPV6) | | defined (CONFIG_IPV6_MODULE)

    union (

    struct ipv6_pinfo af_inet6;

    ) net_pinfo;

    # endif

    union (

    struct tcp_opt af_tcp;

    # if defined (CONFIG_INET) | | defined (CONFIG_INET_MODULE)

    struct raw_opt tp_raw4;

    # endif

    # if defined (CONFIG_IPV6) | | defined (CONFIG_IPV6_MODULE)

    struct raw6_opt tp_raw;

    # endif/* CONFIG_IPV6 */

    # if defined (CONFIG_SPX) | | defined (CONFIG_SPX_MODULE)

    struct spx_opt af_spx;

    # endif/* CONFIG_SPX */

    ) tp_pinfo;

    int err, err_soft;/* Soft holds errors that don't

    cause failure but are the cause

    of a persistent failure not just

    'timed out' */

    unsigned short ack_backlog;

    unsigned short max_ack_backlog;

    __u32 priority;

    unsigned short type;

    unsigned char localroute;/* Route locally only */

    unsigned char protocol;

    struct ucred peercred;

    int rcvlowat;

    long rcvtimeo;

    long sndtimeo;

    # ifdef CONFIG_FILTER

    /* Socket Filtering Instructions */

    struct sk_filter * filter;

    # endif/* CONFIG_FILTER */

    /* This is where all the private (optional) areas that don't

    * overlap will eventually live.

    */

    union (

    void * destruct_hook;

    struct unix_opt af_unix;

    # if defined (CONFIG_INET) | | defined (CONFIG_INET_MODULE)

    struct inet_opt af_inet;

    # endif

    # if defined (CONFIG_ATALK) | | defined (CONFIG_ATALK_MODULE)

    struct atalk_sock af_at;

    # endif

    # if defined (CONFIG_IPX) | | defined (CONFIG_IPX_MODULE)

    struct ipx_opt af_ipx;

    # endif

    # if defined (CONFIG_DECNET) | | defined (CONFIG_DECNET_MODULE)

    struct dn_scp dn;

    # endif

    # if defined (CONFIG_PACKET) | | defined (CONFIG_PACKET_MODULE)

    struct packet_opt * af_packet;

    # endif

    # if defined (CONFIG_X25) | | defined (CONFIG_X25_MODULE)

    x25_cb * x25;

    # endif

    # if defined (CONFIG_AX25) | | defined (CONFIG_AX25_MODULE)

    ax25_cb * ax25;

    # endif

    # if defined (CONFIG_NETROM) | | defined (CONFIG_NETROM_MODULE)

    nr_cb * nr;

    # endif

    # if defined (CONFIG_ROSE) | | defined (CONFIG_ROSE_MODULE)

    rose_cb * rose;

    # endif

    # if defined (CONFIG_PPPOE) | | defined (CONFIG_PPPOE_MODULE)

    struct pppox_opt * pppox;

    # endif

    # ifdef CONFIG_NETLINK

    struct netlink_opt * af_netlink;

    # endif

    # if defined (CONFIG_ECONET) | | defined (CONFIG_ECONET_MODULE)

    struct econet_opt * af_econet;

    # endif

    # if defined (CONFIG_ATM) | | defined (CONFIG_ATM_MODULE)

    struct atm_vcc * af_atm;

    # endif

    # if defined (CONFIG_IRDA) | | defined (CONFIG_IRDA_MODULE)

    struct irda_sock * irda;

    # endif

    # if defined (CONFIG_WAN_ROUTER) | | defined (CONFIG_WAN_ROUTER_MODULE)

    struct wanpipe_opt * af_wanpipe;

    # endif

    ) protinfo;

    /* This part is used for the timeout functions. */

    struct timer_list timer;/* This is the sock cleanup timer. */

    struct timeval stamp;

    /* Identd and reporting IO signals */

    struct socket * socket;

    /* RPC and TUX layer private data */

    void * user_data;

    /* Callbacks */

    void (* state_change) (struct sock * sk);

    void (* data_ready) (struct sock * sk, int bytes);

    void (* write_space) (struct sock * sk);

    void (* error_report) (struct sock * sk);

    int (* backlog_rcv) (struct sock * sk,

    struct sk_buff * skb);

    void (* destruct) (struct sock * sk);

    );

    Ця структура дуже широко використовується і має багато hacks залежних від конфігурації як бачимо для кожного протоколу тут знайдеться містечко

    Сокети проходять через процес маршрутизації тільки один раз для кожного маршруту. Вони містять покажчик на маршрут struct sock - > dst_cache * і викликають ip_route_connect (net/route.h) для знаходження маршруту інформація записується в dst_cache і сокет далі використовує її не повторюючи операції пошуку маршруту поки не станеться щось незвичайне в цьому і є сенс connect

    Встановлення з'єднання

    Розглянемо стандартний приклад

    /* look up host */

    server = gethostbyname (SERVER_NAME);

    /* get socket */

    sockfd = socket (AF_INET, SOCK_STREAM, 0);

    /* set up address */

    address.sin_family = AF_INET;

    address.sin_port = htons (PORT_NUM);

    memcpy (& address.sin_addr, server-> h_addr, server-> h_length);

    /* connect to server */

    connect (sockfd, & address, sizeof (address ));

    socket створює обєкти сокета певного типу і ініціалізує його також робить дефолтівських черги (incoming, outgoing, error, backlog) і заголовок TCP

    connect визначає маршрути викликаючи протокольно залежні функції (tcp_v4_connect (), udp_connect ()) net/socket.c

    asmlinkage long sys_connect (int fd, struct sockaddr * uservaddr, int addrlen)

    (

    ................................

    err = sock-> ops-> connect (sock, (struct sockaddr *) address, addrlen,

    sock-> file-> f_flags);

    ..........................

    )

    int sock_create (int family, int type, int protocol, struct socket ** res)

    (

    .....................................

    // Створити протокольно залежний сокет!

    //--------------------------------------

    if ((i = net_families [family] -> create (sock, protocol)) <0)

    (

    sock_release (sock);

    goto out;

    )

    .................

    )

    Опції

    Socket

    Перевіряємо помилки

    Виділяємо пам'ять

    Ложім сокет в список inode

    Встановлюємо покажчики на протокольно залежні частини

    Зберігаємо дані про тип і параметри сокета

    Встановлюємо сокет в положення закрито

    Ініціалізіруем черги пакетів

    Connect

    Перевіряємо помилки

    Визначаємо Маршрут

    Перевіряємо кеш

    Дивимося в FIB

    Створюємо новий запис в таблиці маршрутизації

    Заповнюємо її і повертаємо

    Зберігаємо покажчик на запис маршрутизації в сокеті

    Викликаємо протокольно залежну функцію connect

    Встановлюємо сокет в сполучений

    Також треба не забути закрити сокет

    Close викликає sock_close in socket.c

    void sock_release (struct socket * sock)

    (

    if (sock-> ops)

    sock-> ops-> release (sock);

    ...........................

    )

    а та через ланцюжок викликів протокольнозавісімую функцію

    Додаткові функції

    void inet_sock_release (struct sock * sk) -net/ipv4/af_inet.c

    назвніе говорить за себе + хороший коментар Алана Коха

    fib_lookup () - include/net/ip_fib.h

    повертає маршрут. Написана російською-Кузнецов!

    fn_hach_lookup net/fib_hash.c

    повертає маршрут за адресою

    inet_create net/ipv4/af_inet.c

    створює сокет

    inet_release

    ip_route_connect

    викликає ip_route_output для визначення адреси призначення

    ip_route_output

    ip_route_output_slow

    rt_intern_hash корисні для маршрутизації функції

    sock_close ()

    sock_create ()

    sock_init_data net/core/sock.c ініціалізує основні поля сокета

    sock_release net/socket.c

    sys_socket

    tcp_close net/ipv4/tcp.c

    встановлює прапор FYN

    tpc_connect net/ipv4/tpc_output.c

    сохдает пакети для з'єднання з встановленим розміром вікна

    і відповідними бітами, кладе пакет в чергу і виpивает

    tcp_transmit_skb щоб послати пакет

    tcp_transmit_skb -заповнює заголовок пакета і передає його

    на уроветь IP

    tcp_v4_connect ()

    викликає ip_route_connect

    створює з'єднувальний пакет і викликає tcp_connect

    udp_close

    udp_connect

    Ця частина описує процес обміну даними між різними рівнями ядра та мережі Коли програма відправляє дані то воно пише в сокет той у своб чергу визначає свій тип і викликає відповідну функцію, та передає дані протоколу транспортного рівня (tcp, udp) функції етого рівня створюють структуру sk_buff, копіюють в неї дані заповнюють заголовок свого рівня, вважають контрольну суму і шлють на рівень IP.Там дописується заголовок ip, checksum, можливо пакет фраг ментору і шле на xmit чергу мережевого девайса, той посилає пакет у мережу.

    dev_queue_xmit () - net/core/dev.c

    spin_lock_bh () -блокуємо девайс

    якщо у нього є черга

    calls enqueue () додаємо пакет

    calls qdis () пробуджує девайс

    else calls dev-> hard_start_xmit ()

    calls spin_unlock_bh () звільняємо девайс

    DEVICE-> hard_start_xmit () - залежить від девайса, drivers/net/DEVICE.c

    в Загалом перевіряє відкрито чи пристрій

    посилає заголовок

    говорить системної шини послати пакет

    оновлює статус

    inet_sendmsg () - net/ipv4/af_inet.c

    int inet_sendmsg (struct socket * sock, struct msghdr * msg, int size,

    struct scm_cookie * scm)

    (

    struct sock * sk = sock-> sk;

    /* бінді сокет. */

    if (sk-> num == 0 & & inet_autobind (sk)! = 0)

    return -EAGAIN;

    викликаємо функцію протоколу щоб послати дані

    return sk-> prot-> sendmsg (sk, msg, size);

    )

    ip_build_xmit - net/ipv4/ip_output.c (604)

    calls sock_alloc_send_skb () виділяємо пам'ять

    = заголовочек =

    if (! sk-> protinfo.af_inet.hdrincl) (

    iph-> version = 4;

    iph-> ihl = 5;

    iph-> tos = sk-> protinfo.af_inet.tos;

    iph-> tot_len = htons (length);

    iph-> frag_off = df;

    iph-> ttl = sk-> protinfo.af_inet.mc_ttl;

    ip_select_ident (iph, & rt-> u.dst, sk);

    if (rt-> rt_type! = RTN_MULTICAST)

    iph-> ttl = sk-> protinfo.af_inet.ttl;

    iph-> protocol = sk-> protocol;

    iph-> saddr = rt-> rt_src;

    iph-> daddr = rt-> rt_dst;

    iph-> check = 0;

    iph-> check = ip_fast_csum ((unsigned char *) iph, iph-> ihl);

    err = getfrag (frag, ((char *) iph) + iph-> ihl * 4,0, length-iph-> ihl * 4);

    )

    calls getfrag () копіюємо дані у юзера

    returns rt-> u.dst.output () [= dev_queue_xmit ()]

    ip_queue_xmit () -- net/ipv4/ip_output.c (234)

    Cмотри маршрут

    добудовує ip заголовок

    фрагментірум якщо треба

    adds IP checksum

    calls skb-> dst-> output () [= dev_queue_xmit ()]

    qdisc_restart () -- net/sched/sch_generic.c (50)

    вириває пакет з черги

    calls dev-> hard_start_xmit ()

    оновлюємо статистику

    if якщо помилка знову стввім пакет у чергу

    sock_sendmsg () - net/socket.c (325)

    перевіряємо права і таке інше

    calls scm_sendmsg () [socket control message]

    шлемс дані

    calls sock-> ops [inet] -> sendmsg () and destroys scm

    >>> sock_write () -- net/socket.c (399)

    calls socki_lookup () accоцііруем сокету до inode

    заповнюємо заголовок повідомлення

    returns sock_sendmsg ()

    tcp_sendmsg () - net/ipv4/tcp.c (755)

    ждемс з'єднання

    skb = tcp_alloc_pskb пам'ять

    calls csum_and_copy_from_user () робимо checksum & копіюємо

    calls tcp_send_skb ()

    tcp_send_skb () -- net/ipv4/tcp_output.c (160)

    це головна routine посилки буфера

    ми ставимо буфер в чергу і вирішуємо залишити його там або послати

    calls __skb_queue_tail () додаємо в чергу

    calls tcp_transmit_skb () якщо може

    tcp_transmit_skb () -- net/ipv4/tcp_output.c (77)

    будуємо заголовок tcp і чексумму

    calls tcp_build_and_update_options ()

    перевіряємо ACKs, SYN

    calls tp-> af_specific [ip] -> queue_xmit ()

    udp_getfrag () - net/ipv4/udp.c

    копіюємо з адресного простору користувача і додаємо checksum

    udp_sendmsg () - net/ipv4/udp.c

    перевіряємо прапори і тд

    заповнюємо заголовок

    перевіряємо мультікаст

    заповнюємо маршутних інформацію

    calls ip_build_xmit ()

    оновлюємо статистику udp

    returns err

    Отримання даних

    Отримання даних починається з переривання від мережевої карти. Драйвер девайса виділяє пам'ять і пересилає дані в той простір. Потім передає пакет у сполучний рівень який викликає bottom-halv, яке обробляє подія поза переривання пересилаючи дані на рівень вище-ip.Тот перевіряє помилки фрагменти, маршрутизируют пакет або відсилає на рівень вище (tcp | | udp) Цей рівень знову перевіряє помилки визначаютьсяет сокет якому призначений пакет і кладе його в чергу сокета. Той у свою чергу будить користувальницький процес і копіює дані в його буфер.

    Читання з сокета (1)

    Намагаємося щось прочитати (і засипаємо)

    Заповнюємо заголовок повідомлення дороговказом на буфер (сокет)

    перевіряємо прості помилки

    передаємо повідомлення inet сокет

    Отримання пакета

    Пробудження пристрої (переривання)

    перевірка девайса

    Отримання заголовка

    виділення пам'яті

    ложім пакет в те місце судячи з усього використовуючи DMA

    ставимо пакет в чергу

    виставляємо прапор запуску bottom-halv

    BottomHalv

    Запуск мережевого ботом-халва

    Пересилання пакетів з девайса щоб не було переривань

    пересилання пакетів на рівень ip

    очищення черги відсилання

    повернення

    Рівень IP

    Перевірка помилок

    Дефрагментація якщо необхідно

    Визначення маршруту (форвард чи ні)

    Відсилання пакету за призначенням (TCP | | UDP | | forwarding)

    Отримання пакету в UDP

    Перевірка помилок

    перевірка сокета призначення

    пересилання пакету в чергу сокета

    пробудження чекаючего процесу

    Отримання TCP

    Перевірка прапорів і помилок а також чи не був отриманий пакет раніше

    Визначення сокета

    пересилання пакету в чергу сокета

    пробудження чекаючего процесу

    Читання з сокета (2)

    Пробудження процесу

    Виклик соответствуюшей функції доставки (udp | | tcp) в буфер користувача

    Повернення

    IP forwarding

    Розглянемо докладніше процес форвардинг пакетів

    Спочатку йде перевірка TTL і зменшення його на 1 Перевірка пакету на наявність дійсного маршруту якщо такого немає то відсилається відповідне icmp повідомлення копіювання пакету в новий буфер і звільнення старого Установка потрібних ip опцій фрагменторованіе якщо необхідно відправка пакету на потрібний девайс

    DEVICE_rx () девайсно залежна функція,

    приклад drivers/net/de600.c

    тут я спробую перевести чудові коментарі автора

    Linux driver for the D-Link DE-600 Ethernet pocket adapter.

    *

    * Portions (C) Copyright 1993, 1994 by Bjorn Ekwall

    * The Author may be reached as [email protected]

    /*

    * Якщо у нас хороший пакет то забираємо його з адаптера

    */

    static void

    de600_rx_intr (struct net_device * dev)

    (

    struct sk_buff * skb;

    unsigned long flags;

    int i;

    int read_from;

    int size;

    register unsigned char * buffer;

    save_flags (flags);

    cli ();

    /* Визначаємо розмір пакету */

    size = de600_read_byte (RX_LEN, dev); / * Нижній байт */

    size + = (de600_read_byte (RX_LEN, dev) 1535)) (

    printk ( "% s: Bogus packet size % d.n ", dev-> name, size);

    if (size> 10000)

    adapter_init (dev);

    return;

    )

    skb = dev_alloc_skb (size +2);

    if (skb == NULL) (

    printk ( "% s: Couldn't allocate a sk_buff of size% d.n ",

    dev-> name, size);

    return;

    )

    /* Інакше */

    skb-> dev = dev;

    skb_reserve (skb, 2);/* Align */

    /* 'skb-> data' указивет на початок буфера даних. */

    buffer = skb_put (skb, size);

    /* копіюємо пакет у буфер */

    de600_setup_address (read_from, RW_ADDR);

    for (i = size; i> 0; - i, + + buffer)

    * buffer = de600_read_byte (READ_DATA, dev);

    /* Визначаємо тип протоколу

    skb-> protocol = eth_type_trans (skb, dev);

    /* Передаємо на верхній рівень см net/core/dev.c

    netif_rx (skb);

    /* оновлюємо статистику */

    dev-> last_rx = jiffies;

    ((struct net_device_stats *) (dev-> priv)) -> rx_packets + +;/* кількість отримань */

    ((struct net_device_stats *) (dev-> priv)) -> rx_bytes + = size;/* кількість отриманих байт */

    /*

    * Якщо трапиться щось погане під час доставки, netif_rx ()

    * зробило a mark_bh (INET_BH) для нас і буде працювати

    * коли ми ввійдемо в bottom-halv.

    */

    )

    ip_finish_output () net/ipv4/ip_output

    визначає девайс для даного маршруту

    викликає функцію девайса [= dev_queue_xmit]

    ip_forward -net/ipv4/ip_forward

    в це фото гарні коментарі

    перевіряємо роутер

    якщо пакет нікому не призначений то Дропан

    якщо поганий TTL аналогічно

    якщо неможет пакет отфорвардітся то відправляємо icmp пакет ICMP_DEST_UNREACH

    якщо необхідно шолом пакет ICMP HOST REDIRECT

    копіюємо і знищуємо старий пакет

    зменшуємо TTL

    якщо необхідно встановлюємо необхідні параметри ip_forward_options в

    ip_forward_finish функція отримання ip пакета

    перевіряємо помилки

    погана довжина

    версія

    чексумма

    викликаємо pskb_trim

    викликаємо ip_route_input

    Процес маршрутизації

    Як вже говорилося є тоюліца сусідів, FIB, routing cache Таблиця сусідів містить адреси (mac) комп'ютерів які фізично з'єднані з нами. Linux використовує АRP для визначення адрес ета таблиця динамічна хоча адміністратори можуть задати статичні записи. Стуктури пов'язані з етой таблицею описані в include/net/neighbour.h основні структури. struct neigh_table-їх цілий зв'язаний список struct neigh_parms-список містить різноманітну статистику struct neighbour-hash таблиця сусідів асоційованих з цією таблицею struct pneig_entry-hash всіх девайсів

    поля struct neighbour

    struct net_device-девайс

    hh_cache -вказівник на апаратний кеш

    sk_buff_head arp_queuq-чергу arp пакетів

    є local-в ній знаходяться свої інтерфейси

    і main в ній напевно все інше

    Forwarding Information Database

    struct fib_table в include/net/ip_fib.h

    містить покажчики на різні функції

    tb_stamp

    tb_id -255 Для local і 254 для main

    td_data-hash fib таблиця

    struct fn_hash -net/ipv4/fib_hash.c

    struct fn_zone * fn_zones [33]-вказівники на зони

    struct fn_zone * fn_zone_list вказівник на перший не порожню зону

    struct fn_zone містить інформацію про зону і маршрути для неї

    struct fib_node ** fz_hash-вказує на кеш записів цієї зони

    int fz_nent кількість записів

    int fx_divisor числа Бакет для зони (в основному 16 крім зони 0000

    loopback девайса)

    int fz_order індекс зони в батьківській fn_hash

    struct fib_node-містить інформацію по девайсу в fib_info (include/net/ip_fib.h)

    метрику , протокол і т.д

    Routing Cache

    Це найбільш швидкий спосіб знаходження маршруту Коли ip потрібний маршрут, то він визначає комірку в хеше, що вказує на ланцюжок маршрутів і йде з цієї ланцюжку поки не знайде потрібний маршрути мають таймери і частоту використання , найбільш часті переміщуються по тексту.

    struct rtable-ланка в ланцюжку

    містить адреси відправника та одержувача

    вхідний інтерфейс

    адреса сусіда або шлюзу

    struct dst_entry

    містить спецефіческіх для даного маршруту характеристики та функції

    struct dev-зрозуміло

    pmtu максимальна довжина пакета для даного маршруту

    int (* input) (struct sk_buff)-вказівник на функцію прийому для даного маршруту

    часто ето tcp_rcv

    int (* output) (struct sk_buff) покажчик на функцію відсилання (dev_queue_xmit)

    також різноманітні статистичні дані та опції

    Таким чином нами було проведено дослідження мережної архітектури операційної системи Линух на прикладі реалізації стека протоколів tcp-ip версії 4 в ядрі 2.4.7

    Додаток

    Після тривалих теоретичних досліджень можна застосувати їх на практиці

    Нашої метою буде створення зручного для користувача інтерфейсу для зазначення в пакеті підставного ip адреси (адреса якого немає у жодного нашого інтерфейсу) Я не буду показувати, то як адреси виставляються в ядрі. Зауважу лише те що, з сокета сімейства AF_INET і типу SOCK_RAW пакет з не своєю адресою відправити начебто можна (в ядрі 2.2, насчет 2.4 невпевнений-може там є якісь перевірки). сторінки мана говорять про опцію IP_HDRINCL. Їх можна відправляти також через тип SOCK_PACKET. Але для всього цього знати код ядра не дуже необхідно. Тому ми підемо іншим шляхом.

    Найбільш легкий шлях (?) зробити це через інтерфейс setsockopt. Після уважного вивчення коду функції sys_setsockopt -net/socket.c знаходимо рядки if ((sock = sockfd_lookup (fd, & err))! = NULL)

    (

    if (level == SOL_SOCKET)

    err = sock_setsockopt (sock, level, optname, optval, optlen);

    else

    err = sock-> ops-> setsockopt (sock, level, optname, optval, optlen);

    sockfd_put (sock);

    )

    return err;

    )

    значить нам треба шукати функцію setsockopt в коді для реалізації для типу sock_raw це файл net/ipv4/raw.c дивимося static int raw_setsockopt (struct sock * sk, int level, int optname,

    char * optval, int optlen)

    (

    if (level! = SOL_RAW)

    return ip_setsockopt (sk, level, optname, optval, optlen);

    ...................................

    ) ip_setsockopt лежить в net/ipv4/ip_sockglue.c в ній йде довгий перебір опцій ми зупинимо свій вибір на рівні SOL_IP і додамо в перебір свої рядки/* HACK :>>>>>>>>>>>>>>>*/

    # ifdef CONFIG_HACKIP

    case IP_HACKIP:

    printk ( "HACKIP: setsockopt flag % dn ", sk-> hackflag);

    sk-> hackflag = 1;

    get_user (val, (int *) optval);

    printk ( "HACKIP: setsockopt val % dn ", val);

    sk-> hackf.src_addr = val;

    break;

    # endif

    case IP_HDRINCL:

    докладніше опишемо відбуваються дії

    printk -виводимо отлабочние повідомлення

    Я не впевнений, але судячи з усього при створенні сокета вся структура обнуляється тому ми можемо не дивитися прапор. Я додав цей рядок, щоб подивитися завжди Чи він дорівнює 0 при не встановленій опції а після установки при повторі він дорівнює 1. get_user забираємо значення, подробиці include/asm/uaccess.h але для всього цього нам треба додати відповідні поля у struct sock ======= sock.h =============

    .........................

    # ifdef CONFIG_HACKIP

    /* HACK :>>>>>>>>>>>>>>>>>>*/

    struct ip_hack (

    __u32 src_addr;

    );

    # endif

    struct sock (

    /* Socket demultiplex comparisons on incoming packets. */

    .................................

    # ifdef CONFIG_HACKIP

    /* HACK :>>>>>>>>>>>>>>>>>*/

    struct ip_hack hackf;

    int hackflag;

    # endif

    ........................................

    =========== end ======================

    тепер нам треба перехопити відправку пакету

    йдемо у файл net/ipv4/ip_output.c і після всіх рядків де є 'iph-> saddr =' вставляємо наш код # ifdef CONFIG_HACKIP

    if ((sk-> hackf.src_addr! = 0) & & (sk-> hackflag == 1))

    (

    iph-> saddr = sk-> hackf.src_addr;

    printk ( "HACKIP: ip_build_and_send .. % dn ", iph-> saddr);

    )

    # endif

    Залишилось мале: у файл include/linux/in.h додаємо рядок # define IP_HACKIP 16

    в файл net/Config.in

    bool 'HACKIP facilities' CONFIG_HACKIP робимо

    cd/usr/src/linux

    make menuconfig

    make dep

    make bzImage

    cp arh/i386/boot/bzImage / boot/kursach

    правим lilo.conf або/boot/grub/menu.lst

    соответствуюшая команда

    reboot ....

    тепер протестуємо нашу програму перепрошую за можливу наявність зайвих include просто я переробив файл з друго-го проекту

    ============ rel.c ========================

    /* Written by Gleb Paharenko  2003 */

    /* Посвящяется Кевин Митник */

    /* і прекрасної весни в травні 2003-го */

    # include

    # include

    # include

    # include

    # include

    # include

    # include

    # include

    # include

    # define IP_HACKIP 16

    int main ()

    (

    int sd, res;

    int value = 1;

    int sval = 0;

    int oval = 1;

    char buffer [100];

    struct sockaddr_in addr, raddr;

    bzero (buffer, sizeof (buffer ));

    if ((sd = socket (PF_INET, SOCK_RAW, 6))

         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status