그간 SOCK_PACKET은 sniffer (tcpdump...)에서 패킷 빼올때나 쓰는것줄 알았는데 패킷을 보낼 때도 쓰더라..
packet socket도 raw socket과 비슷하게 application 단에서 패킷을 비교적 자유롭게 보내기 위해 사용되는데... - 내가 봤던 코드는 GARP를 전송하는 코드였뜸 -
문득 raw 와 packet socket의 차이점에 대해 궁금해 졌다.

차이점은 아래와 같다.
http://www.developerweb.net/forum/showthread.php?t=4981
Raw socket
1. Layer3까지 조작이 가능하다.
2. 일반적인 network stack을 이용한다.
3. 커널이 처리하기 전에 먼저 빼올 수 있다.
4. sockaddr_in을 사용한다.

=>raw socket도 hooking이 가능해야 한다는 말이다!

Packet socket
1. Layer2까지 조작이 가능하다.
2. network stack을 skip하고 device driver로 전송된다.
3. 커널이 처리하기 전에 먼저 빼올 수 있다.
4. sockaddr_ll을 사용한다.

=>hooking이 안된단 말이다!

큰 차이점을 요약하면
어느 layer까지 조작이 가능한가와 일반적인 network stack을 통과하느냐 그렇지 않느냐의 차이겠다. 

나에게 있어 header 조작이야 그냥 그렇고(지겨움 ^^;) network stack skip에 대한 부분은 매우 흥미로웠다.
만약 packet socket이 정말로 device driver (e1000..) 단으로 빠져 버린다면 net-filter에서 어떤 처리 (NAT, FW..)도 할 수 없다는 결론이 나온다.
어찌 관심을 안가질 수 있으리오..?

포스팅은 포스팅일 뿐이므로, - 이건 100% 신뢰 할 수 없다는 얘기다! - 
정말 그런지는 kernel source를 확인하는게 언제나 진리다 ^^;

이에 앞서 raw와 socket에 얽힌 이야기를 먼저 해보자.
- 위 원문에 RobSeace 씨가 한 얘기다 이분 왠지 포스 있다 -

Raw socket은 거의 BSD 표준을 따랐으며 유닉스 계열의 시스템에서 사용된다.
그 목적은 IP위에 올라갈 수 있는 사용자 단의 protocol을 쉽게 설계하도록 하는 거였지만,
몇몇 사람만 이렇게 쓰는것 같다.
<<< 넉두리 시작
 - 사실 누가 열라 시간을 들여가며 IP 바로 윗단의 (이말은 TCP, UDP, ICMP 등등을 사용하지 않는 다는거죠~) Layer를 만들 겠수? 만든다고 해도 kernel단의 network stack에 통합하지 복잡하게 user space에 만들지는 안을거유 (이말은 와닿지 않는다) -
>>> 넉두리 끝
요세는 ICMP 메시지를 주고 받는데 주로 사용되는것 같다. (맞는 말이죠??)

Packet socket은 Linux 독자적인 특성으로 다른 시스템에는 없다. 
하지만 각 시스템들은 표준에 동의하지 않았기 때문에 비슷한 역할을 수행하는 some을 가지고 있다. - 이게 여러분이 libpcap과 같은 higher-level library를 사용하는 이유다 -
어쨋든, 주된 차이점은 packet socket이 network-layer 보다는 link-layer에서 수행되는게 맞다.
때문에 여러분은 IP 트래픽 외에도 모든 종류의 트래픽을 sniffing 할수 있다.

- 이상 조사 끝, 코드 분석 시작 (아 근데 RobSeace 너무 스마트해 보여서 부럽다. 투덜대는거 빼고) -

자 그럼 packet이 정말 network stack을 skip하는 지에 대해 알아보자. 우훗우훗

가정:
packet socket의 경우 network stack을 skip 하므로 
sendto api 호출 시 초기 단계에서 dev_queue_xmit 혹은 hard_start_xmit을 call 할 것이다.

상콤하게 sock_sendmsg부터 가자

1. sock_sendmsg
필요한 것만 보자.
__sock_sendmsg에서 sock->ops->sendmsg를 call 한다.
역시나 virtual function~ 아 귀차나~~
af_packet.c를 뒤져보자!!
후훗 차자뜸

2. packet_sendmsg
등록은 packet_create 가 한다. 
sock->ops = &packet_ops; 

오!!!!! 굳굳 일단 가설은 적중 lol 
함수 마지막 부분을 보면 

     /*
     *    Now send it
     */

    err = dev_queue_xmit(skb);
    if (err > 0 && (err = net_xmit_errno(err)) != 0)
        goto out_unlock;

    dev_put(dev);

    return(len);

명확하다!! 난 이런게 좋다 ^_^
dev_queue_xmit -> hard_start_xmit -> e1000_xmit_frame (intel)

엄밀히 말하면 device driver로 곧바로는 아니지만 (dev_queue_xmit에서 queuing 처리를 하므로)
이정도는 애교로 봐줄 만 하다.
이는 또한 sock_packet이 hooking이 되지 않는 이유도 명확히 설명된다.

참고로 이 function을 보면 routing 역시 skip 하는걸 볼 수 있다.
dev = dev_get_by_index(ifindex); // output device를 얻어오고
...
skb->dev = dev; // 그대로 집어 넣는다.

이말은 application에서 반드시 해당 정보들을 설정해 주어야 한다는 것이다.

[출처] SOCK_RAW verse SOCK_PACKET|작성자 데비



출 처 : http://blog.naver.com/realbright1?Redirect=Log&logNo=94508080

■ OSI 7 LAYER

스위치의 종류는 OSI(Open Systems Interconnection) 7 Layer(계층)에서 정의한 계층별 스위치로 기종이 서로 다른 컴퓨터간의 정보교환을 원활히 하기 위해 국제표준화기구 ISO에서 제장한 것으로, 네트워크를 이루고 있는 구성 요소들을 계층적 방법으로 나누고 각 계층의 표준을 정한 것이다.

계층별 명칭과 역활을 보면


1 Layer - 물리계층
- 최하위계층으로 장치간의 물리적인 접속을 제어하기 위한 기능을 제공하는 계층
- 데이터 부호화 방식,신호형식, 데이터 충돌 감지 등을 정의
- 대표적인 프로토콜 : ITU-T 권고안 중 V.24, EIA의 RS-232C

2 Layer - 데이터 링크 계층
- 물리계층에서 사용되는 통신 매체를 통해 데이터 블록의 전송 에러 검출 및 에러 제어를 관리하고 규정하는 계층
- 대표 프로토콜 : HDLC, SDLC, LAP-B

3 Layer - 네트워크 계층
- 통신망에 연결된 시스템의 데이터 전송과 교환 기능을 담당하는 계층
- 복수 개의 통신망을 이용하고 있는 시스템을 위한 계층
- 대표 프로토콜 : ITU-T 권고안의 X.25

4 Layer - 전송계층
- 링크 종점간에 정확한 데이터 전송을 제공하는 계층
- 하위 계층과 상위계층의 인터페이스 역할
- 데이터 전송에 대한 오류검출, 오류복구, 흐름제어를 수행

5 Layer - 세션계층
- 사용자와 전송 계층간의 인터페이스로 사용자 접속 장치를 제공하는 계층
- 세션 접속 설정, 데이터 전송, 세션 접속 해제 등의 기능
- 데이터 전송 도중 에러가 발생하면 통신을 중단하고 재전송 기능을 수행

6 Layer - 표현계층
- 응용 프로그램 사이에 서로 다른 정보의 형식과 설정과 암호화등을 해독하여 서로연결이 가능하도록 하는 계층
- 데이터의 구문 검색, 코드변환, 재구성을 통해 구문상의 차이를 해결

7 Layer  - 응용계층
- 최상위 계층으로 통신망으로 연결된 응용 프로세서들의 정보교환이 되는 계층

- 하위계층과 상위계층으로 나눈다.
   > 하위계층(물리계층, 데이터링크계층, 네트워크계층)
       - 데이터 전송 기능을 담당하는 계층으로 인접 노드간의 데이터 전송과 목적지 까지의 데이터 전송을 담당
   > 상위계층(전송계층, 세션계층, 표현계층, 응용계층)
      - 통신처리 기능을 담당하는 계층으로 파일, 데이타베이스에 대한 엑세스 작업

이와 같이 7 계층으로 나누어 전한 기능과 명칭을 간략히 요약해서 실무에서 많이 사용하고 있는 것이 각 계틍별 구분보다는 스위치로 통칭하여 그 기능과 역활을 사용하고 있다.

 

■ L2, L3, L4, L7 스위치 차이점

어떤 주소를 가지고 스위칭을 하는가에 따라 L2,L3,L4 스위치로 구분된다.

L2는 MAC주소, L3은 프로토콜 주소, L4는 세션 프로토콜을 이용하여 스위칭할 수 있다.

 

1. L2 스위치 : 스위칭 허브 기능

  . 데이터링크 계층에 위치하여 서로 다른 데이터링크간을 스위치해주는 장비

   . 패킷의 MAC 주소를 읽어 스위칭을 하고, MAC이 OSI 계층 중 2 계층에 해당하기 때문에 Layer 2 스위치라 한다.

   . 기본적인 동작은 브리지나 스위칭 허브는 모든 자료를 보내는 곳으로 수신 번지를 전송한다.

   . 장점 : 구조가 간단하며, 신뢰성이 높다. / 가격이 저렴하고, 성능이 높다.

     단점 : Broadcast 패킷에 의해 성능 저하가 발생한다. - 라우팅이 불가능 / 상위 레이어 프로토콜을 이용한 스위칭이 불가능 하다.

 

2. L3 스위치 : 라우터 기능

  . 네트워크 계층에 위치하여 서로 다른 네트워크간을 연결해 주는 장비(즉,  데이터의 네트워크 주소를 보고 스위칭해주는 장비)

   .해당 프로토콜을 쓰는 패킷을 스위칭이 가능하며, IP나 IPX 주소가 OSI 7 계층 중 3 계층에 해당하기 때문에 Layer 3 스위치라 한다.

  . L2 스위치에 라우팅(Routing) 기능을 추가하고, 대부분의 고성능 하드웨어를 기초로 하였다. - 기본 구성은 L2와 동일

  . 장점 : Broadcast 트래픽으로 전체 성능 저하를 막을 수 있다. / 트래픽 체크, 가상 랜 등의 많은 부가 기능을 갖고 있다.

    단점 : 특정 프로토콜을 이용해야 스위칭을 할 수 있다. / 대부분의 트래팩이 서브텟의 한계를 넘는다.

 

3. L4 스위치 : 로드 벨런싱 기능 (서버부하분산 및 조정)

  . L3과 같이 프로토콜을 기반으로 하며, 어플리케이션별로 우선 순위를 두어 스위칭이 가능하다.

   . 여러대의 서버를 1대처럼 묶을 수 있는 부하 분산 (Load Balancing) 기능을 제공한다.

   . 웹 트래픽, FTP 트래픽과 같이 정해진 서비스 포트를 보고 트래픽을 스위칭해주는 장비

                      웹 포트가 80 이니 FTP는 21이니 하는 것이 이 포트를 말함

   . 장점 : 보안성이 높고 고급 스위칭 설정이 가능하다. - 상황에 적절한 설정 /  용량에 관계 없이 네트워크의 성능 개선에 기여한다.

   . 단점 : 프로토콜에 의존적이며, 설정이 복잡하다. / 고가의 장비로 L2,L3 스위치와 적절한 혼합 배치가 필요하다.

 

4. L7 스위치 : 데이터 안의 실제 내용까지 조회해 보고 특정 문자열이나 특정 명령을 기준으로 트래픽을 스위칭

   . 더 상세한 패킷을 처리하므로 패킷의 부하분산, QOS기능이 가능

   . Dos/SYN Attack에 대한 방어

   . CodeRed/Nimda등 바이러스 감염 패킷의 필터링

   . 네트워크 자원의 독점 방지를 통한 네트워크 시스템의 보안성 강화가 가능함

 

 

■ L2, L3, L4 차이점 개략

스위치 레벨  공통점 차이점 설명
 L2  모두 IP Address 가지고 있음
(반드시는 아니지만 가질수있음)
더미허브, 스위치허브가 있으며, Switch의 역활만 함
MAC을 이용한 패킷전송
 L3 Hub + Router의 역활을 수행하는 장비
스위칭허브에 라우팅기능이 추가된 장비로 다른 네트워크끼리 통신가능
IP를 이용한 패킷전송
 L4 여러대의 서버를 1대처럼 묶어서 트래픽의 로드발랜싱 기능 제공
균등하게 트래픽 분배하는 스위치
프로토콜을 이용한 통신

출 처 :  http://blog.naver.com/kingwjt?Redirect=Log&logNo=110130734235

1	filter.txt: Linux Socket Filtering
2	Written by: Jay Schulist <jschlst@samba.org>
3	
4	Introduction
5	============
6	
7		Linux Socket Filtering is derived from the Berkeley
8	Packet Filter. There are some distinct differences between
9	the BSD and Linux Kernel Filtering.
10	
11	Linux Socket Filtering (LSF) allows a user-space program to
12	attach a filter onto any socket and allow or disallow certain
13	types of data to come through the socket. LSF follows exactly
14	the same filter code structure as the BSD Berkeley Packet Filter
15	(BPF), so referring to the BSD bpf.4 manpage is very helpful in
16	creating filters.
17	
18	LSF is much simpler than BPF. One does not have to worry about
19	devices or anything like that. You simply create your filter
20	code, send it to the kernel via the SO_ATTACH_FILTER ioctl and
21	if your filter code passes the kernel check on it, you then
22	immediately begin filtering data on that socket.
23	
24	You can also detach filters from your socket via the
25	SO_DETACH_FILTER ioctl. This will probably not be used much
26	since when you close a socket that has a filter on it the
27	filter is automagically removed. The other less common case
28	may be adding a different filter on the same socket where you had another
29	filter that is still running: the kernel takes care of removing
30	the old one and placing your new one in its place, assuming your
31	filter has passed the checks, otherwise if it fails the old filter
32	will remain on that socket.
33	
34	Examples
35	========
36	
37	Ioctls-
38	setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter));
39	setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &value, sizeof(value));
40	
41	See the BSD bpf.4 manpage and the BSD Packet Filter paper written by
42	Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory.

sendto

 

sendto 함수는 지정된 주소로 데이터를 전송하는 함수입니다.

 

int sendto (
        SOCKET  
s,
        const char FAR *  
buf,
        int  
len,
        int  
flags,
        const struct sockaddr FAR *  
to,
        int 
 tolen
);

 

Parameters

s
[입력] 소켓의 기술자를 명시합니다.

buf
[입력] 전송될 데이터를 가지고 있는 버퍼

len
[입력] 버퍼 않에 있는 데이터의 길이

flags
[입력] 
함수의 호출이 어떤일을 할지 나타내는 플래그 입니다.

to
[입력] 데이터가 전송될 원격 호스트의 어드레스를 나타냅니다.

tolen
[입력] 
to 매개변수의 크기

Remarks

sendto 함수는 소켓(접속 되었건 접속되지 않았건)에서 데이터를 접속된 상대방으로 전송하는데 사용되는 함수입니다. 메시지 지향 소켓(message-oriented sockets)에서 최대 패킷크기(getsockopt 함수로 SO_MAX_MSG_SIZE 옵션의 값을 얻어내서 최대 크기를 구할 수 있습니다.)를 초과하지 않도록 주의 해야 합니다. 만약 데이터가 전송되기에 너무 크다면, 데이터는 전송되지 않고, WSAEMSGSIZE 에러코드를 발생합니다.

to 매개변수는 소켓의 주소체계(address family)로 된 데이터가 전송될 원격 호스트의 어드레스를 나타냅니다. 물론, 브로드캐스트(broadcast) 또는 멀티캐스트 어드레스(multicast address)도 될 수 있습니다. 브로드캐스트 어드레스를 사용하여 전송할 경우 어플리케이션은 SO_BROADCAST 소켓옵션을 가능하게 하여 getsockopt 함수를 호출해야 합니다. getsockopt 함수를 이용하지 않고, 브로드캐스트 하려 한다면, sendto 함수는 실패로 돌아가고, WSAEACCES 에러코들 발생하게 됩니다. TCP/IP 에서, 어플리케이션은 그룹멤버(group member)가 되지 않고도 특정한 멀티캐스트 어드레스로 데이터를 전송할 수 있습니다.

소켓이 바인드 되지 않은 경우 유일한 값은 로컬 시스템에 의해서 할당되어 집니다. 그런다음 소켓은 바운드 된 것 처럼 마킹 됩니다. 이런 경우 어플리케이션은 로컬 소켓의 이름(name)을 얻기 위해 getsockname 함수를 사용할 수 있습니다.

send 함수의 성공적인 종료가 성공적인 데이터의 전송을 의미하지는 않는다는 점을 명심하세요.

sendto 함수는 일반적으로 접속되지 않은 소켓에 대해서, to 매개변수에 지정된 특정한 상대방 소켓으로 데이터그램을 전송하는데 사용하는 함수입니다. 하지만, 소켓(connectionless sockets : SOCK_DGRAM)이 이전에 특정한 주소로 접속되어 있다 하더라도, to 매개변수는 이전에 명시된 목적지 주소를 무시합니다. 접속지향소켓(connection-oriented socket)의 경우 to 와 tolen 매개변수는 무시되며, sendto 함수는 send 함수와 같은 작동을 하게 됩니다.

flag 매개변수는 소켓에 대해 명시된 옵션 이상의 함수동작에 영향을 미치기 위해서 사용될 수 있습니다. 함수의 의미체계는 소켓옵션 그리고, flag 매개변수에 의해서 결정되어 집니다. flag 매개변수를 이용한 방법의 경우 아래의 값을 OR 비트연산을 취해서 구성되어 집니다.

ValueMeaning
MSG_DONTROUTE
 

데이터는 라우팅 될 수 없음을 나타냅니다. 윈도우즈 소켓 시스템은

 대응하는 소켓옵션과 마찬가지로 이 값을 무시 할 수 있습니다.

MSG_OOB

데이터가 out-of-band 데이터로서 전송될 수 있음을 나타냅니다.

이 플래그는 스트림 소켓과만 사용됩니다.

Return Values

에러가 발생하지 않는다면, send 함수는 전송된 총 데이터 크기를 반환합니다. 비동기 소켓의 경우len 매개변수로 건넨 수치보다 작을 수 있습니다. 에러가 발생한 경우는 SOCKET_ERROR를 반환하고, WSAGetLastError를 이용해서 특정한 에러코드를 얻어낼 수 있습니다.

Error Codes

WSANOTINITIALISED

이 함수를 사용하기 전에 성공적인 WSAStartup 함수의 호출이

없었습니다.

WSAENETDOWN 네트웍 서브 시스템에 에러가 발생했습니다.
WSAEACCES

요청된 주소가 브로트캐스트(broadcast) 주소인데, 적절한

플래그가 셋팅되어 있지 않습니다. 브로드캐스트 어드레스의

사용을 허용하기 위해 SO_BROADCAST 매개변수를 가지고,

setsockopt 함수를 호출 해야 합니다.

WSAEINVAL

알 수 없는 플래그가 사용되었거나, SO_OOBINLINE 옵션을

가능하게 한 상태 에서 MSG_OOB 플래그가 소켓에 대해서

명시되었습니다. 또는 len 매개변수가 0 이거나 0보다 작습니다.

WSAEINTR

블록킹 호출이 WSACancelBlockingCall 함수에서

취소되었습니다.

WSAEINPROGRESS

블럭킹 윈속 v1.1 이 현재 진행 중이거나, 서비스 프로바이더가

콜백 함수를 여전히 처리하고 있습니다.

WSAEFAULT buf 매개변수가 제대로 된 형태가 아닙니다.
WSAENETRESET 연산이 진행되고 있는 도중 접속이 끊겨버렸습니다.
WSAENOBUFS 전송하기 위해 사용할 수 있는 버퍼 공간이 없습니다.
WSAENOTCONN 소켓이 접속된 상태가 아닙니다.
WSAENOTSOCK 기술자(descriptor)가 소켓 기술자가 아닙니다.
WSAEOPNOTSUPP

MSG_OOB 가 명시되었지만, 소켓은 SOCK_STREAM 과 같은

형태의 스트림 형태가 아닙니다.

WSAESHUTDOWN 소켓이 셧다운 되었습니다.
WSAEWOULDBLOCK

소켓이 넌블록킹(비동기)로 마킹되어 있고, 수신 연산이 블록킹

상태입니다.

WSAEMSGSIZE

소켓이 메시지 지향형(message oriented)이고, 메시지의

크기가 허용할 수 있는 최대 크기 보다 큽니다.

WSAEHOSTUNREACH

네트웍 시스템 장애 등에 의해서 원격호스트까지 도달 할 수

없습니다.

WSAECONNABORTED

가상 연결 회로망이 타임아웃이나 다른 실패 때문에 끊어져

버렸습니다.

WSAECONNRESET

가상 회로망이 원격지에서 "hard"나 "abortive" 종료를 수행해서

리셋되었습니다.

WSAEADDRNOTAVAIL

원격지 주소가 올바를 형태가 아닙니다. 예를들어 ADDR_ANY와

 같은 형태는 잘못된 형태입니다.

WSAEAFNOSUPPORT 지정된 어드레스 체계가 이 소켓에서 사용될 수 없습니다.
WSAEDESTADDRREQ 목적지 주소가 필요합니다.
WSAENETUNREACH 웍격 시스템까지 네트웍이 도달할 수 없습니다.
WSAETIMEDOUT

접속이 네트웍 실패나 상대방 시스템의 응답 실패로 인하여 드랍

되어 버렸습니다.

 

QuickInfo

Windows NT : 사용가능
Windows : 사용가능
Windows CE : 버젼 1.0 그리고 그이후의 버젼에서 사용가능
Header :
          Win16/32 : winsock.h
          Win32-II : winsock2.h
Import Library :
          Win16 : winsock.lib
          Win32 : wsock32.lib
          Win32-II : ws2_32.lib

 

See Also

overviewrecvrecvfromselectsendsocketWSAAsyncSelectWSAEventSelect

 

 

출처 : DEVPIA 곽용진님 style  APIs

[출처] [Socket] sendto|작성자 임종배

http://softwaredocuments.blogspot.com/2009/10/294-linux-and.html



Linux: SOCK_PACKET and PF_PACKET


There are two methods of receiving packets from the datalink layer under Linux. The original method, which is more widely available but less flexible, is to create a socket of type SOCK_PACKET. The newer method, which introduces more filtering and performance features, is to create a socket of family PF_PACKET. To do either, we must have sufficient privileges (similar to creating a raw socket), and the third argument to socket must be a nonzero value specifying the Ethernet frame type. When using PF_PACKET sockets, the second argument to socket can be SOCK_DGRAM, for "cooked" packets with the link-layer header removed, or SOCK_RAW, for the complete link-layer packet. SOCK_PACKET sockets only return the complete link layer packet. For example, to receive all frames from the datalink, we write


fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));        /* newer systems*/
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)); /* older systems*/
This would return frames for all protocols that the datalink receives.

If we wanted only IPv4 frames, the call would be


fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));          /* newer systems */
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP)); /* older systems */
Other constants for the final argument are ETH_P_ARP and ETH_P_IPV6, for example.

Specifying a protocol of ETH_P_xxx tells the datalink which frame types to pass to the socket for the frames the datalink receives. If the datalink supports a promiscuous mode (e.g., an Ethernet), then the device must also be put into a promiscuous mode, if desired. This is done with a PACKET_ADD_MEMBERSHIP socket option, using a packet_mreq structure specifying an interface and an action of PACKET_MR_PROMISC. On older systems, this is done instead by an ioctl of SIOCGIFFLAGS to fetch the flags, setting the IFF_PROMISC flag, and then storing the flags with SIOCSIFFLAGS. Unfortunately, with this method, multiple promiscuous listeners can interfere with each other and a buggy program can leave promiscuous mode on even after it exits.


Some differences are evident when comparing this Linux feature to BPF and DLPI:


  1. The Linux feature provides no kernel buffering and kernel filtering is only available on newer systems (via theSO_ATTACH_FILTER socket option). There is a normal socket receive buffer, but multiple frames cannot be buffered together and passed to the application with a single read. This increases the overhead involved in copying the potentially voluminous amounts of data from the kernel to the application.

  2. SOCK_PACKET provides no filtering by device. (PF_PACKET sockets can be linked to a device by calling bind.) IfETH_P_IP is specified in the call to socket, then all IPv4 packets from all devices (Ethernets, PPP links, SLIP links, and the loopback device, for example) are passed to the socket. A generic socket address structure is returned by recvfrom, and the sa_data member contains the device name (e.g., eth0). The application must then discard data from any device in which it is not interested. The problem again is too much data can be returned to the application, which can get in the way when monitoring a high-speed network.

bind

 

bind 함수는 로컬 인터페이스 어드레스와 포트번호를 소켓과 서로 연관되게 묶는 함수입니다.

 

int bind (
    SOCKET 
s,
    const struct sockaddr FAR* 
name,
    int 
namelen
);

 

Parameters

s
[입력] 로컬어드레스와 아직 묶여지지 않은 소켓 기술자(descriptor).

name 
[입력] 소켓에 할당하기위한 
SOCKADDR 구조체로 이루어진 주소.

namelen 
[입력] 
name 매개변수의 크기 (일반적으로 sizeof(SOCKADDR) 요로케 쓰입니다).

 

Remarks

처음 만들어 질 때 소켓은 그와 관련된 로컬 어드레스를 가지지 않습니다. 따라서 bind 함수는connect 나 listen 함수를 뒤이어 호출하기 전에, 접속되지 않은 소켓에 사용됩니다. 이 함수는 접속지향형소켓(stream socket : TCP)이나 비접속(datagram : UDP) 소켓 이나 모두 사용합니다. 소켓이 socket 함수를 호출해서 생성될 때, 소켓은 이름공간(name space)에 존재합니다. 하지만, 할당된 이름을 가지지는 않습니다. 그러므로, 이름 지여지지 않은 소켓과 로컬 어드레스를 연결지우기 위해서 이 함수는 사용됩니다.

이 함수에 의해서 할당되어 지는 이름은 세가지 부분으로 구성됩니다. (인터넷 주소 체계를 사용할 때 : 주소체계(address family), 호스트주소(host address), 어플리케이션에 사용되는 포트번호(port number)) WinSock2 에서는 name 매개변수는 SOCKADDR 구조체의 포인터로 반드시 넘겨야 한다라는 그런 규정은 없습니다. 그저 윈도우즈 소켓 1.1 과의 호환성 때문에 남았는 산물정도라고 생각해 두세요. 서비스 프로바이더는 namelen 의 메모리 사이즈 블록 포인터에 대해 연관을 받지 않습니다. 메모리 블록에서 첫번째 2Byte (SOCKADDR 구조체의 sa_family에 해당되는 부분입니다) 는 소켓을 생성하는데 사용되는 어드레스 체계(address family)를 가지고 있어야 합니다. 그렇지 않다면, WSAEFAULT 에러가 발생 할 것입니다.

만약 어플리케이션이 어떤 로컬 어드레스를 할당 할 것인지 고려하지 않고 사용된다면, name 매개변수의 sa_data 멤버를 위해 INADDR_ANY 라는 상수값을 명시해야 합니다. 이 상수값을 사용하면, 적절한 네트웍 주소를 사용하기 위해 기본이되는 서비스 프로바이더를 적용하게 됩니다. 이 상수값은 한 개 이상의 네트웍 인터페이스나 주소가 있는 호스트일 경우 어플리케이션 프로그래밍을 간략히 하기 위해서 사용됩니다. 대부분의 프로그램은 인터페이스 어드레스에 대해 INADDR_ANY를 사용합니다.

TCP/IP에서 포트번호가 0으로 명시된 경우에는 서비스 프로바이더가 어플리케이션을 위한 고유한 포트번호(1024~5000 사이의 값)를 할당합니다.  어플리케이션은 주소와 포트를 알기위해 bind 된 후에 getsockname 함수를 사용할 수 있습니다. 만약 인터넷 주소가 INADDR_ANY 로 사용되어 있다면, getsockname 함수는 접속되기 전까지는 사용하지 못합니다. (몇몇 주소들은 호스트가 multihome 일 경우 올바를 수도 있기 때문입니다) 0번 포트가 아닌 특정한 포트 번호를 바인딩하는 것은 클라이언트 어플리케이션을 무용지물이 되게 합니다. 왜냐하면, 다른 소켓에 이미 그 포트 번호를 사용하고 있을 경우 충돌 할 수 있는 위험이 있기 때문입니다. 따라서, 클라이언트 프로그램이 포트 0을 지정하는 반면, 서버 프로그램은 대개 자신의 포트 번호를 지정합니다.

connect  함수를 호출하기 전에는 bind 함수와 같이 소켓과 어드레스를 묶는 함수가 사실상 필요치 않습니다. 소켓이 묶이기 전에 connect 함수가 호출될 경우 bind 함수가 INADDR_ANY 의 어드레스와 포트 번호 0을 이용하여 소켓에 대해 호출된 것처럼 소켓은 자동으로 묶이게 됩니다. 대부분의 클라이언트 어플리케이션은 로컬 인터페이스 어드레스나 특별한 포트 값을 지정할 필요가 없습니다. 따라서 bind함수를 호출하기 전에 connect 함수를 호출함으로써 이들 어플리케이션에 대한 단계를 줄일 수 있습니다. 일반적으로 서버 어플리케이션은 Well-known 포트와 묶인 소켓을 생성해야 합니다. 이를 위해 bind 함수는 대부분 서버에 대해 명확하게 호출되어야 합니다.

Windows CE : IrSocket 에서의 구현...

  • Af_irda.h를 포함 시켜주어야 합니다.
  • SOCKADDR_IRDA_wcesdk_SOCKADDR_IRDA 구조체가 addr 매개변수로 사용됩니다.
  • WSAENETDOWN 에러코드는 지원되지 않습니다.
  • INADDR_ANY와 같은 와일드 카드 주소는 지원되지 않습니다.

    IrSocket 클라이언트는 connect 함수를 사용하기 전에 bind 함수를 호출해야 합니다. 만약 서비스 이름이 "LSAP-SELxxx"형태(xxx는 0~255사이의 십진 정수) 라면, 주소는 서비스 이름 보다 특정한 LSAP-SEL xxx를 의미합니다. LSAP-SELxxx 서비스 이름은 IAS를 발생하지 않을 것입니다. 소켓은 특정한 IAS를 무시한 LSAP-SEL을 직접적으로 묶을것입니다.

Return Values

에러가 없는 경우 0을 리턴합니다. 에러가 발생한 경우는 SOCKET_ERROR을 리턴합니다. 그리고,WSAGetLastError 함수를 호출해서 특정한 에러코드를 리턴 할 수 있습니다.

Error Codes

WSANOTINITIALISED

이 함수를 사용하기 전에 성공적인 WSAStartup 함수의 호출이

 없었습니다.

WSAENETDOWN

네트웍 서브 시스템에 에러가 발생했습니다.

WSAEADDRINUSE
 
 

프로세스가 이미 같은 어드레스로 바운드 되어있고, 소켓이

SO_REUSEADDR로 재 사용 어드레스라는 항목을 마크 하지

않았습니다. 한 예로, IP 주소와 포트가 af_inet 경우로 바운드

되어있는 경우입니다. (setsockopt 함수에 의한 SO_REUSEADDR

소켓 옵션에 대해서 참고하세요)

WSAEADDRNOTAVAIL 지정된 주소가 정확한 주소가 아닙니다.
WSAEFAULT
 
 

name이나 namelen 매개변수가 올바르지 않습니다. namelen 매개

변수가 너무 작거나, name 매개변수가 연관된 주소체계에 대해서

잘못된 주소 형태를 포함하고 있습니다. 또는, 메모리 블록의

첫 번째 2Byte 가 소켓 기술자 s와 연관된 주소체계와 일치하지

않습니다.

WSAEINPROGRESS

블럭킹 윈속 v1.1 이 현재 진행 중이거나, 서비스 프로바이더가

콜백 함수를 여전히 처리하고 있습니다.

WSAEINVAL 소켓이 이미 특정주소와 바인드 되어 있습니다.
WSAENOBUFS 너무 많은 접속으로 인하여 버퍼가 충분하지 않습니다.
WSAENOTSOCK

기술자(descriptor)가 소켓 기술자가 아닙니다.

 

 

QuickInfo

Windows NT : 사용가능
Windows : 사용가능
Windows CE : 버젼 1.0 그리고 그이후의 버젼에서 사용가능
Header :
          Win16/32 : winsock.h
          Win32-II : winsock2.h
Import Library :
          Win16 : winsock.lib
          Win32 : wsock32.lib
          Win32-II : ws2_32.lib

See Also

overviewconnectgetsocknamelistensetsockoptsocketWSACancelBlockingCall

 

 

출처 : DEVPIA 곽용진님 style  APIs

[출처] [Socket] bind|작성자 임종배

리눅스에 SOCK_PACKET이라는 소켓이 있는데, 이것을 이용하면 어떤 MAC 프레임도 만들어서 전송할 수 있다. 사용방법은 코드를 보면 쉽게 알수 있다. 그리고, root만 가능하다. (ether_wake.c 를 참조하여 작성하였음.)

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <sys/socket.h>
 
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <sys/socket.h>

int send_packet(char *ifname, unsigned char *outpack, int pktsize)
{
        struct sockaddr whereto;
        int s;
        int one=1;
        int i;
 
        if ((s = socket(AF_INET, SOCK_PACKET, SOCK_PACKET)) < 0) {
                if (errno == EPERM)
                        fprintf(stderr, "send_packet must run as root\n");
                else
                        perror("send_packet: socket");
        }
 
        /* Don't revert if debugging allows a normal user to get the raw socket. */
        setuid(getuid());
 
        if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)) < 0)
                perror("setsockopt: SO_BROADCAST");
 
        whereto.sa_family = 0;
        strcpy(whereto.sa_data, ifname);
 
        if ((i = sendto(s, outpack, pktsize, 0, &whereto, sizeof(whereto))) < 0)
                perror("sendto");
 
        return 0;
}

PF_PACKET 초간단 강좌
일반적인 소켓은 TCP 또는 UDP 데이터를 다룬다. 바꾸어 말하자면 소켓을 이용해서 주고 받는 데이터는 TCP(또는 UDP) 레이어의 데이터 뿐이라는 것이다. 그 이하 레이어는 보낼때나 받을때 신경을 쓸 필요가 없는것이다. 우리가 데이터를 건데면 커널은 알아서 IP 헤더와 이더넷 헤더를 붙여서 보내주고, 받을때도 앞의 헤더들을 다 띄어내고 TCP/UDP 데이터만 건데 준다.

이러한 방식은 일반적으로 편리하지만, 때로는 TCP이하의 레이어를 건드려야만 할때가 있다. 이럴때 사용할 수 있는 것이 바로 Raw소켓이다. 하지만 Raw소켓은 IP레이어까지만 조작이 가능하다. 만약에 이더넷 레이어까지 건드리고 싶다면 어떻게 해야 할까.

가장 좋은 해결책은 pcap라이브러리를 사용하는 것이다. pcap은 다양한 플랫폼에 포팅되어있으므로 이식성 좋은 코드를 작성할 수 있다. 하지만 리눅스에서만 쓸것이라면 단연 PF_PACKET을 추천한다. PF_PACKET은 특정한 라이브러리 없이 일반적인 소켓을 사용하는 것과 유사하게 이더넷 레이어까지 조작할수있는 방법을 제공한다.

사용법은


socket(PF_PACKET, int socket_type, int protocol);

이런식으로 소켓생성시에 PF_PACKET을 명시해주면 된다. 너무 간단한가? 그것이 바로 이 PF_PACKET의 장점이다. 이렇게 생성된 소켓은 작성한 데이터를 원하는 레이어까지 그대로 전달한다. 단지 주소를 표시할때, sockaddr_ll 구조체를 사용해야하는 점이 다르다.

예를 들어 다음의 코드를 보자


struct icmp_packet
{
      struct ethhdr eth;
      struct iphdr ip;
      struct icmphdr icmp;
      char data[1472];
} __attribute__ ((packed)); 

int sock;
struct icmp_packet packet;
struct sockaddr_ll dest;

sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL);
dest.sll_family = PF_PACKET;
dest.sll_protocol = htons(ETH_P_IP);
dest.sll_ifindex = 사용하고자하는 인터페이스의 인덱스;
memcpy(dest.sll_addr, 받을 대상의 MAC,6);

// packet의 내용을 적당히 잘 채워준다 (체크섬까지 해야하는거 알죠!)

sendto(sock, &packet, sizeof(icmp_packet), 0, (struct sockaddr *) &dest, sizeof(dest));

라고한다면, 이미 이더넷 헤더와 IP헤더를 포함하고 있는 packet을 바로 네트워크로 보내버린다(따로 IP헤더를 만들지도 않고 ARP도 하지않는다).

사용법을 정리하자면,
1. PF_PACKET으로 소켓을 연다.
2. 이더넷 레이어까지 포함하는 데이터를 만든다.
3. sockaddr_ll 구조체에 받을 대상의 MAC을 넣는다.
4. send!

이렇게 할 경우 이더넷 레이어까지 사용자가 원하는대로 조작이 가능해진다. 위의 예는 PING을 쏠때, 발신자의 이더넷 주소를 조작하기 위한 코드의 일부분이다. 이런 방식을 응용한다면, 이더넷 소스 어드레스를 바꿔 보낸다던지 하는 조작이 가능하다(ARP패킷을 만들어서 보낼수도 있다).

만약에 이더넷 레이어를 포함한 패킷전체를 받고싶다면, bind를 이용하면된다. 일단 참고문서는 man packet(man 페이지 답게 그렇게 자세하지는 않다). UNP최신판에는 PF_PACKET에 대해 나와있다고 하는데, 확인해보지는 않았다.

Posted by jungjun at 2004년 11월 04일 06:07 PM | 리눅스 다이어리 
TrackBack URL: http://jungjun.net/mt/mt-tb.cgi/43 

setsockopt

 

setsockopt 함수는 소켓 옵션을 설정하는 함수입니다.

 

int setsockopt (
        SOCKET 
 s,

        int  
level,
        int 
 optname,
        const char FAR *
  optval,
        int  
optlen
);

 

Parameters

s
[
입력대상 소켓의 기술자(descriptor)를 명시합니다.

 

level
[
입력소켓 옵션 레벨이 정의 되며, SOL_SOCKET  IPPROTO_TCP 중 하나가 될 수 있습니다.

 

optname
[
입력셋팅 하기위한 소켓옵션 값입니다.

 

optval
[
입력검색된 옵션을 저장 하기위한 데이터 버퍼를 포인트 합니다.

 

optlen
[
입력optval 매개변수 버퍼의 크기

 

Remarks

setsockopt 함수는 지정된 소켓의 옵션을 특정한 형태(type), 상태(state)로 결합하기 위해서 지정한 소켓옵션 값을 셋팅하는 함수입니다비록 여러 프로토콜 레벨로의 소켓 옵션이 존재 할 순 있다 하더라도가장 우선하는 레벨이 존재하게 됩니다옵션은 소켓 연산에 영향을 미칩니다예를들어 발송된 데이터(OOB 데이터를 예로 들 수 있습니다를 일반 데이터 스트림으로 수신했을때나소켓으로 브로드캐스트(broadcast) 메세지를 전송할때 영향을 미치게 됩니다.

이 함수에서 사용 할 수 있는 두가지 형태의 소켓옵션이 있습니다활성화 또는 비활성화 시키기 위한 Boolean 옵션과수형(integer) 또는 구조체를 요구하는 옵션이 있습니다. Boolean 옵션을 활성화 하기 위해서 optval 매개변수는 0이 아닌 정수를 포인트 하고비활성화 하기 위해서  0을 포인트 합니다optlen 매개변수는 Boolean 옵션에 대해서는 sizeof(int)로 설정 해야만 합니다다른 옵션들에 대해서optval 매개변수는 설정하고자 하는 정수(integer)나 구조체를 넘겨야 하고optlen 매개변수는 정수(integer) 또는 구조체의 길이를 넘겨야 합니다아래에 setsockopt 함수에서 사용 할 수 있는 옵션들을 간단한 설명과 함께 나열 해 보았습니다.

level = SOL_SOCKET

옵션값(Value)

데이터형태(Type)

의미(Meaning)

SO_BROADCAST 
 

BOOL
 

소켓으로 브로드캐스트(broadcast) 메세지를 전송 할 수 있도록 합니다.

SO_DEBUG

BOOL

디버깅 정보를 레코딩 합니다.

SO_DONTLINGER


BOOL


 

소켓을 종료(close)할때 보내지지 않은 데이터를 보내기위해서 블럭킹 상태가 되지 않도록 합니다이 옵션을 셋팅하는 것은 LINGER구조체의 멤버중 l_onoff 0으로 셋팅하고SO_LINGER 옵션을 셋팅 했을때와 같은 효력을 발휘합니다.

SO_DONTROUTE

BOOL

라우팅 하지 않고직접 인터페이스로 보냅니다.

SO_GROUP_PRIORITY




 

int




 

차후에 소켓그룹을 사용하기위해 예약 되어있습니다소켓그룹의 일부분인 소켓을 만들기위해 관련된 우선사항을 명시합니다
(
우아아아악정말 해석 못해 먹겠네여... 원문을 첨가 하겠습니다

Reserved for future use with socket groups. Specify the relative priority to be established for sockets that are part of a socket group.

SO_KEEPALIVE

BOOL

Keepalives를 전송합니다.

SO_LINGER
 

struct LINGER
 

아직 전송되지 않은 데이터가 있을 경우 소켓을 종료(close)할때 대기합니다.

SO_OOBINLINE
 

BOOL
 

일반 데이터 스트림(normal data stream)으로 out-of-band 데이터를 수신합니다.

SO_RCVBUF

 

int

 

데이터를 수신하기 위한 총 버퍼공간을 명시합니다요놈은 SO_MAX_MSG_SIZE , TCP Window의 크기와 상관이 없습니다.

SO_REUSEADDR
 

BOOL
 

이미 사용되고 있는 어드레스를 바인드 할 수 있도록 합니다.

SO_SNDBUF

 

int

 

데이터를 전송하기 위한 총 버퍼공간을 명시합니다요놈은 SO_MAX_MSG_SIZE , TCP Window의 크기와는 상관이 없습니다.

level = IPPROTO_TCP

TCP_NODELAY
 

BOOL
 

전송합병(send coalescing)을 위해Nagle 알고리즘을 비 활성화 합니다.

 

Return Values

에러가 발생하지 않으면setsockopt 함수는 0을 반환합니다에러가 발생하면, SOCKET_ERROR을 반환하면WSAGetLastError 함수를 이용해서 특정 에러 코드를 얻어낼 수 있습니다.

 

Error Codes

WSANOTINITIALISED

이 함수를 사용하기 전에 성공적인 WSAStartup 함수의 호출이 없었습니다.

WSAENETDOWN

네트웍 서브 시스템에 에러가 발생했습니다.

WSAEFAULT

optval 또는 optlen 매개변수 중의 하나가 올바르지 않거나 optlen 매개변수의 값이 너무 작습니다.

WSAEINPROGRESS

블럭킹 윈속 v1.1 이 현재 진행 중이거나서비스 프로바이더가 콜백 함수를 여전히 처리하고 있습니다.

WSAEINVAL

level 매개변수가 잘못됐거나알 수 없는 값 입니다.

WSAENETRESET

SO_KEEPALIVE가 설정 되었을때접속이 타입아웃 되었습니다.

WSAENOPROTOOPT

알 수 없는 옵션이거나지원지지 않는 옵션을 사용 했습니다.

WSAENOTCONN

SO_KEEPALIVE가 설정 되었을때접속이 리셋 되었습니다.

WSAENOTSOCK

기술자(descriptor)가 소켓 기술자가 아닙니다.

 

QuickInfo

 

Windows NT : 사용가능
Windows : 
사용가능
Windows CE : 
버젼 1.0 그리고 그이후의 버젼에서 사용가능
Header :
          Win16/32 : winsock.h
          Win32-II : winsock2.h
Import Library :
          Win16 : winsock.lib
          Win32 : wsock32.lib
          Win32-II : ws2_32.lib

See Also

overviewbindgetsockoptioctlsocketsocketWSAAsyncSelectWSAEventSelect

소켓 생성 시 어떤 책은 PF_INET를 쓰고, 어떤 책은 AF_INET 를 사용합니다.

PF_INET는 프로토콜 체계(프로토콜 패밀리)중 하나이고,

AF_INET는 주소 체계(주소 패밀리)중 하나입니다.

 

프로토콜 패밀리는 아래와 같은 종류가 있습니다.

 프로토콜 체계(Protocol Family)  정의
 PF_INET IPv4인터넷 프로토콜
 PF_INET6 IPv6인터넷 프로토콜
 PF_LOCAL LOCAL 통신을 위한 UNIX 프로토콜
 PF_PACKET Low level socket을 위한 인터페이스
 PF_IPX IPX 노벨 프로토콜
 

소켓을 만들 때는 소켓이 사용될 환경을 고려해 프로토콜을 설정해 주어야 합니다.

다시 말해 프로토콜 패밀리는 소켓을 생성할 때 이 소켓이 어떤 프로토콜을 사용해 통신을 할지 정해줍니다.

참고로 소켓은 네트워크 통신을 할때만 사용되는 것은 아닙니다.

유닉스 계열의 시스템에서 시스템 내부의 프로세스들끼리 통신을 하기 위해서도 사용됩니다.

자주 사용되는 PF_INET는 프로토콜 패밀리중 하나입니다.

 

AF_INET는 주소 패밀리중 하나입니다.  종류는 아래와 같습니다.

 주소체계(Address Family) 정의
 AF_INET  IPv4인터넷 프로토콜
 AF_INET6  IPv6인터넷 프로토콜
 AF_LOCAL  LOCAL 통신을 위한 UNIX 프로토콜

 

이 들은 주소 구조체 안에 주소 패밀리를 정의할 때 사용합니다.

 

프로토콜 체계를 나타내는 PF_INET와 주소체계를 나타내는 AF_INET 는 같은 상수 값을 가지고 있습니다.

그렇다고 해서 주소정보를 설정하는 부분에 PF_INET를 사용하고 프로토콜 패밀리 정보를 설정하는 부분에 AF_INET를 넣는 것은 좋지 않습니다.

 

결과적으로, 프로토콜 체계를 설정하는 부분은 PF로 시작하는 상수를 사용하고, 주소 체계를 설정하는 부분은 AF로 시작하는 상수를  사용하는 것이 좋습니다.

 

실제 코딩 부분에서 socket()함수에 프로토콜 패밀리에 AF_INET를 넣어도 되지만 PF_INET를 넣는게 바람직하고

struct sockaddr_in 구조체에 주소 체계를 넣을 때에도 PF_INET 를 넣어도 되지만 AF_INET를 넣는게 바람직하다.

출처 : http://blog.naver.com/l18400?Redirect=Log&logNo=60109296392

+ Recent posts