Реалізація мережі в операційній системі 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 * divv; / * 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 хеш-таблиця яка містить до 256 ланцюжків маршрутів якщо відповідний маршрут не знайдений в кеші то він додається туди з 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 ** pdivv;

struct sock * bind_next;

struct sock ** bind_pdivv;

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 * divv;

/ * 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)

Дивись маршрут

добудовуємо 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 bj0rn@blox.se

/ *

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

* /

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% dn", 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% dn",

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_rcv net/ipv4/ip_input.c головна функція отримання 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)

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Курсова
50.2кб. | скачати


Схожі роботи:
Складання сценаріїв в операційній системі LINUX
Основи роботи в операційній системі Windows 2
Безпека в мережевій операційній системі FreeBSD
Мережевий друк в операційній системі FreeBSD
Розсилання пошти в мережевій операційній системі FreeBSD
Перевизначення призначень клавіш на клавіатурі в операційній системі Windows
Казка про те як Windows і Linux дружили в одній мережі
Організація безпеки мережі підприємства з використанням операційної системи Linux
Бізнес план розробки навчального курсу по операційній системі OS 2 Warp Connect 4
© Усі права захищені
написати до нас