- Linux Kernel 4.6.3 /net/ethernet/eth.c -


[ /net/ethernet/eth.c - Function 'eth_header' ]


이하의 코드는 eth_header함수의 원형이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int eth_header(struct sk_buff *skb, struct net_device *dev,
           unsigned short type,
           const void *daddr, const void *saddr, unsigned int len)
{
    struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
 
    if (type != ETH_P_802_3 && type != ETH_P_802_2)
        eth->h_proto = htons(type);
    else
        eth->h_proto = htons(len);
 
    if (!saddr)
        saddr = dev->dev_addr;
    memcpy(eth->h_source, saddr, ETH_ALEN);
 
    if (daddr) {
        memcpy(eth->h_dest, daddr, ETH_ALEN);
        return ETH_HLEN;
    }
 
    if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
        eth_zero_addr(eth->h_dest);
        return ETH_HLEN;
    }
 
    return -ETH_HLEN;
}
EXPORT_SYMBOL(eth_header);
cs

[ eth.c - eth_header(...) ]


먼저 매개변수 분석부터 시작하자. 차례대로 skb, dev, type, daddr, saddr, len을 넘겨받고 있다.

skb는 sk_buff*형으로, 이더넷 헤더를 구현할 소켓 버퍼를 가리키고 있는 포인터이다.

dev는 패킷 처리를 위해 참조할 네트워크 디바이스 구조체를 가리키는 포인터.

type은 상위 프로토콜 타입을 나타내고, daddr과 saddr은 각각 Destination과 Source H/W Address를 나타내게 된다. 마지막으로 len은 패킷 길이를 나타내는 매개변수이다.

다음으로는, 루틴을 분석하도록 하겠다. 위 루틴에서 가장 첫 줄에서 ethhdr*형 eth에 skb_push의 리턴 값을 ethhdr*형으로 형 변환해서 대입하고 있는데,  skb_push의 경우 sk_buff를 인자로 받고 있다. 해당 함수는 skbuff.c에 명세 되어 있으며, 간략하게 알아보자면. skb_push함수는 내부적으로 다음과 같은 루틴을 수행하게 된다.


1
2
3
4
5
6
7
8
9
unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
{
    skb->data -= len;
    skb->len  += len;
    if (unlikely(skb->data<skb->head))
        skb_under_panic(skb, len, __builtin_return_address(0));
    return skb->data;
}
EXPORT_SYMBOL(skb_push);
cs

[ skbuff.c - skb_push(...) ]


매개변수로는 sk_buff*형인 skb와 unsigned int형인 len을 받게 되며, 매개변수로 받은 skb의 data멤버(실 버퍼의 시작 위치 포인터)를 len만큼 빼게 되고 (기존 버퍼의 앞쪽에 len만큼 추가적인 공간을 확보), 해당 연산을 통해 확보한 공간을 len멤버(실 버퍼의 크기를 나타내는 멤버)에 더해주게 된다.

정리하자면, eth_header함수의 코드에서는

struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);

를 호출하고 있는데 이를 skb_push()함수의 동작과 함께 정리하자면,

'sk_buff* skb를 skb_push함수에 인자로 넘겨 ETH_HLEN(이더넷 헤더 크기)만큼 추가적인 공간을 버퍼의 앞 부분에 추가적으로 확보한 뒤, 해당 버퍼 포인터를 ethhdr*형(이더넷 헤더 포인터형)으로 변환해서 eth에 저장하게 된다.

여기서 ethhdr구조체가 어떤 구조로 이루어져 있는지 짚고 넘어가도록 하겠다.


1
2
3
4
5
6
struct ethhdr {
        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
        unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
        __be16          h_proto;                /* packet type ID field */
} __attribute__((packed));
 
cs

[ if_ether.h - struct ethhdr ]


ethhdr은 다음과 같은 구조로 되어 있다. 여기서 ETH_ALEN은 #define ETH_ALEN 6으로서 정의되어 있다. 따라서 Octet * 6으로서, ETH_ALEN크기의 uchar배열 h_dest와 h_source는 H/W주소를 나타냄을 알 수 있다. 그 하단에 h_proto는 프로토콜 지정자로서 __be16 (u16 - unsigned short)형으로서, 일반적으로 2Byte를 나타낸다. 이를 실제 이더넷 패킷과 비교하면,



0~13 (Byte)Offset까지 존재하는 EthernetII 헤더와 1 : 1대응이 된다는 것을 알 수 있다.

계속 진행을 해서 다음 코드 부분을 분석해보도록 하겠다.


1
2
3
4
    if (type != ETH_P_802_3 && type != ETH_P_802_2)
        eth->h_proto = htons(type);
    else
        eth->h_proto = htons(len);
cs

[ eth.c - eth_header(...) ]


위 코드에서는 매개변수로 넘겨 받은 type에 들어있는 값이 ETH_P_802_3, ETH_P_802_2 둘 중 어느 것과도 같지 않을 경우, type을 그대로 ethhdr구조체 eth의 h_proto멤버에 대입하게 된다. 즉, 일반적인 EthernetII 헤더와 같이 type값을 넣는다는 것을 알 수 있다.

그러나 type이 ETH_P_802_3 혹은, ETH_P_802_2일 경우에는 h_proto에 len을 넘기게 되는데 이는, IEEE 802.3/802.2와 큰 연관이 있다. 많은 사람들이 IEEE 802.3 자체를 이더넷이라 아는 경우가 많은데, 실제 IEEE 802.3은 좀 더 큰 의미라고 보는 것이 맞을 듯 하다. IEEE 802.3은 EthernetII라고 불리는 DIX II (RFC 894)표준부터, RFC 1042등을 모두 포함한 표준이다. 위의 경우 RFC 1042인 IEEE 802.3 혹은, IEEE 802.2 LLC 프레임을 포함한 IEEE 802.3를 if문을 통해 EthernetII와 구분하게 된다. 이때, h_proto의 위치에 패킷의 길이를 나타내는 len이 들어가는 이유는 아래 IEEE 802.3 Frame의 그림을 보자



위와 같이 기존 EthernetII에서 EtherType에 해당하는 부분이 Length로 대체된 것을 알 수 있다. 커널 코드에서는 이를 반영해 EthernetII가 아닌, IEEE 802.3 Frame기반의 프로토콜은 해당 명세에 맞게 h_proto에 len을 저장하게 된다.

이제 남은 부분을 모두 정리하도록 하겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    if (!saddr)
        saddr = dev->dev_addr;
    memcpy(eth->h_source, saddr, ETH_ALEN);
 
    if (daddr) {
        memcpy(eth->h_dest, daddr, ETH_ALEN);
        return ETH_HLEN;
    }
 
    if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
        eth_zero_addr(eth->h_dest);
        return ETH_HLEN;
    }
 
    return -ETH_HLEN;
cs

[ eth.c - eth_header(...) ]


saddr에 별도로 정의된 값이 없을 경우, 네트워크 디바이스 구조체의 dev_addr멤버에 명시되어 있는 H/W Address를 읽어 memcpy로서 복사하게 된다. net_device는 NIC 마다 커널에 로드되는 네트워크 디바이스 드라이버 고유 구조체로서, 각 NIC마다 독립적인 구조체를 가지고 있다. 이 때 해당 net_device구조체의 dev_addr은 해당 NIC의 MAC주소를 가지게 되며, 따라서 위 코드는 네트워크 통신을 수행할 디바이스에서 직접적으로 MAC주소를 수집해 넣는 것으로 보아도 무방하다.

다음으로, daddr. daddr은 일반적인 경우 특정 값이 전달되기 때문에 그대로 memcpy를 통해 h_source에 복사하면 된다. 이 경우가 위 코드의 5번 라인에서 8번 라인에 해당하는 과정이다. 그러나 일부 특수한 경우 daddr의 값이 정해지지 않은 채로 넘어오는 경우가 있는데(null ptr), saddr의 경우 송신자가 본인인 것을 알 수 있으니까 디바이스에서 주소를 얻어올 수 있다지만 Destination이 정의되지 않은 경우에는 어쩔 수 없이 15번 라인과 같이 -ETH_HLEN이라는 에러코드를 리턴하게 된다.

하지만, 이에도 예외가 있는데 10번 라인에서 12번 라인까지를 살펴보자.


IFF_NOARP(ARP를 수행하지 않는 인터페이스, Destination Address를 설정하지 않음)혹은 IFF_LOOPBACK(루프백 인터페이스)일 경우에는 daddr이 설정되어 있지 않더라도 eth_zero_addr함수를 이용해 memset으로 0x00을 채워주게 된다.


본 함수의 경우 일반적인 루틴을 수행하고 리턴을 한 경우, 7번 라인에서 ETH_HLEN, 즉 이더넷 헤더 길이를 리턴하게 되고, 그 이외의 경우에는 -ETH_HLEN 에러코드를 리턴하여 헤더 할당 도중에 문제가 생겼음을 알린다.

최종적으로 정리하자면, 네트워크 통신을 수행할 sk_buff를 받아서 이더넷 헤더를 추가 및 값을 설정 해주는 함수라고 보면 될 듯 하다.

Posted by RevDev
,

-A lightweight Wi-Fi auto deauthentication attack tool (libtins/C++)-



https://github.com/Revimal/WifiDeauth



'Network' 카테고리의 다른 글

[Network/ARP] ARP Request/Reply  (0) 2016.06.25
[Network/Ethernet] EthernetII header  (0) 2016.06.21
[Network/libtins] Sending ARP, ICMP Packet with libtins  (0) 2016.06.21
Posted by RevDev
,

-ARP Request/Reply-




[ Hardware Type ]

Size : 2 Bytes

Offset : 0 ~ 1


[ Protocol Type ]

Size :  2 Bytes

Offset : 2 ~ 3


[ Hardware Length ]

Size :  1 Bytes

Offset : 4


[ Protocol Length ]

Size :  1 Bytes

Offset : 5


[ Operation ]

Size :  2 Bytes

Offset : 6 ~ 7


[ Sender Hardware Address ]

Size :  6 Bytes

Offset : 8 ~ 13


[ Sender IP Address ]

Size :  4 Bytes

Offset : 14 ~ 17


[ Target Hardware Address ]

Size :  6 Bytes

Offset : 18 ~ 23



[ Target IP Address ]

Size :  4 Bytes

Offset : 24 ~ 27



Hardware Type / Protocol Type :각각 네트워크 유형과 프로토콜을 정의하며, Hardware Type의 경우 Ethernet은 0x0001을 세팅하고 Protocol Type의 경우 IPv4는 0x0800을 세팅하게 됨


Hardware Length / Protocol Length : 각각 MAC주소와 IP주소의 길이를 설정하며, MAC주소의 경우 0x06에서 바뀌는 경우가 없고 Protocol Length의 경우 IPv4일 경우에는 0x04를 세팅하게 됨


Operation : Request Packet의 경우 0x0001을, Reply Packet의 경우 0x0002를 세팅하게 됨


Sender/Target Hardware/IP Address :각각 발신지/목적지의 MAC/IP주소를 명시하며, ARP Request의 경우에는 Target Hardware Address필드를 0x000000000000으로 세팅해서 보내게 됨




[ ARP ]

ARP (Address Resolution Protocol)은 추상적인 주소인 IP주소를 실제 통신에 쓸 수 있는 H/W주소(MAC)으로 변경하는데 필요한 프로토콜이다.


상대방의 IP를 알지만, MAC을 알지 못할 때 Broadcast를 통해 Request를 보내면, 해당 IP를 소유하고 있는 시스템은 자신의 MAC주소를 채워, Request를 한 시스템에게 Unicast방식으로 Reply를 보내게 된다.

Reply를 받은 시스템은 Reply의 Sender Hardware Address필드에서 MAC주소를 알아낼 수 있다.




[ Example ]
A (MAC : 00:1b:78:7b:5d:8c, IP : 192.168.0.1)

B (MAC : 00:13:77:bd:2d:5c, IP : 192.168.0.2)


이 상황에서, A가 B의 IP주소(192.168.0.2)를 알고, H/W주소를 모를경우 다음과 같은 과정을 거치게 된다.


→ B (ARP Request : Broadcast)

[EthernetII Src : 00:1b:78:7b:5d:8c]

[EthernetII Dest : ff:ff:ff:ff:ff:ff]



← B (ARP Reply : Unicast)

[EthernetII Src : 00:13:77:bd:2d:5c]

[EthernetII Dest : 00:1b:78:7b:5d:8c]











Posted by RevDev
,

-Baekjoon Online Judging 11399 - ATM-


[Probs]

https://www.acmicpc.net/problem/11399


[Solve]

그리디 알고리즘...이라고 하기도 민망할 정도로 쉬운 문제였다.

Sorting을 하는 방법과 Priority-Queue를 이용하는 방법이 있다.

하지만 본인의 경우 STL의 multiset이라는 컨테이너를 사용해서 풀었다.

multiset의 경우 기존의 set에서 중복 원소를 허용하는 것으로, insert시 정렬이 가능하다.

priority_queue보다 performance가 우수하며, iteration이 가능해 Range-based for loop에도 사용할 수 있다.


[Code]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <set>
 
int main(){
    int num, tmp, ret = 0;
    std::multiset<intstd::less<int>> vSet;
    std::cin >> num;
    for(int i = 0; i < num; ++i){
        std::cin >> tmp;
        vSet.insert(tmp);
    }
    tmp = 0;
    for(auto x : vSet) {
        tmp = x + tmp;
        ret += tmp;
    }
    std::cout << ret;
}
 
cs

Posted by RevDev
,

-EthernetII header-





[ Preamble ]

Preamble (7) + SFD (1)

Total : 8 Bytes

Offset : #0~#7


[ MAC Header ]

Destination MAC Address (6) + Source MAC Address (6) + Ether Type (2)

Total : 14 Bytes

Offset : 0~13


[ Data ]

PDU Payloads (46 ~ 1500)

Total : 46 ~ 1500 Bytes

Offset : 14 ~ 59 (Min)


[ CRC Checksum ]

CRC Checksum (4)

Total : 4 Bytes

Offset : 60 ~ 63




Preamble,  SFD : 동기 신호로서, 본격적인 프레임 시작 전에 미리 알리는 역할, 이 부분을 기점으로 NIC는 데이터를 Byte단위로 해석하기 시작, EthernetII Header에서 제외하는 경우도 많음


MAC Header : 송, 수신 MAC주소를 각각 6 Bytes (48 bits)로 지정, Ether Type 같은 경우에는 상위 프로토콜이 Patload에 포함되어 있을 경우, 해당 프로토콜의 종류를 서술함.


Data : 상위 프로토콜이나 Raw Data등이 포함되며, 데이터 그 자체임


CRC Checksum : CRC 알고리즘으로 생성된 값을 포함하여 무결성 검사를 수행, 송, 수신 중의 오류 여부를 확인하게 됨




[ 대표적인 Ether Type ]

0x0800 : Internet Protocol Version 4 (IPv4)

0x0806 : Address Resolution Protocol (ARP)

0x0842 : Wake-on-Lan (WOL)

0x8137 : Internet Packet Exchange (IPX)

0x86DD : Internet Protocol Version 6 (IPv6)

0x8808 : Ethernet flow control


Posted by RevDev
,

-Linux Binary Hardening with Glibc-



Linux Binary Hardening with Glibc.pdf

Posted by RevDev
,

-Linux character driver example on 3.19.0-43-generic -


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
 
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
 
static DEFINE_MUTEX(mutexIoctl);
//Mutex for unlocked_ioctl
 
static unsigned char* chpBuf = NULL;
//Device buffer pointer
 
static int memOpen(struct inode *inp, struct file *fp);
static int memRel(struct inode *inp, struct file *fp);
static ssize_t memRead(struct file *fp, unsigned char *chpOut, size_t sztCount, loff_t *loftPos);
static ssize_t memWrite(struct file *fp, const unsigned char __user *chpIn, size_t sztCount, loff_t *loftPos);
static long memIoctl(struct file *fp, unsigned int iNum, unsigned long iParam);
//Device callback functions
 
static struct file_operations fileOpers;
static bool bFlag = false;
//Custom device mutex
 
static int __init kernmodule_init(void)
{
    void *vpErr;
    //Error pointer
    
    fileOpers.read = memRead;
    fileOpers.write = memWrite;
    fileOpers.open = memOpen;
    fileOpers.release = memRel;
    fileOpers.unlocked_ioctl = memIoctl;
    //Allocate callback functions
 
    if(register_chrdev(200"kernmodule", &fileOpers) < 0)
        return -EIO;
    //Register character device (major = 200, device name = kernmodule)
 
    chpBuf = kmalloc(32, GFP_USER);
    if(IS_ERR(vpErr = chpBuf))
        return -ENOMEM;
    memset(chpBuf, 032);
    //Allocate memory area for device buffer
 
}
 
static void __exit kernmodule_exit(void)
{
       unregister_chrdev(200"kernmodule");
       //Unregister character device
 
       if(chpBuf)
        kfree(chpBuf);
}
 
static int memOpen(struct inode *inp, struct file *fp){
    //Device file open
    if(bFlag)
        return -EBUSY;
    bFlag = true;
    return 0;
}
 
static int memRel(struct inode *inp, struct file *fp){
    //Device file release
    bFlag = false;
    return 0;
}
 
static ssize_t memRead(struct file *fp, unsigned char __user *chpOut, size_t sztCount, loff_t *loftPos){
    //read() from device file
    if(sztCount > 32)
        return -1;
    if(bFlag)
        copy_to_user(chpOut, chpBuf, sztCount);
    return sztCount;
}
 
static ssize_t memWrite(struct file *fp, const unsigned char __user *chpIn, size_t sztCount, loff_t *loftPos){
    //write() to device file
    if(sztCount > 32)
        return -1;
    if(bFlag)
        copy_from_user(chpBuf, chpIn, sztCount);
    return sztCount;
 
static long memIoctl(struct file *fp, unsigned int uiNum, unsigned long ulParam)
{
    int iIter = 0;
    mutex_lock(&mutexIoctl);
    //ioctl Routine(User-level application can access with ioctl() function)
    mutex_unlock(&mutexIoctl);
    return 0;
}
//unlocked_ioctl : normal ioctl was deprecated
 
module_init(kernmodule_init);
module_exit(kernmodule_exit);
 
 
cs
Posted by RevDev
,

-Sending ARP, ICMP Packet (libtins Examples)-


[ARP]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <tins/tins.h>
#include <unistd.h>
 
int main()
{
    Tins::PacketSender sender;
    //Libtins packetsender(Virtual L1 Physical Layer)
 
    Tins::IPv4Address target = Tins::IPv4Address("192.168.43.1");
    //Target IP
 
    Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
    Tins::NetworkInterface::Info info = iface.addresses();
    //Get addresses from network interface
 
    Tins::EthernetII eth = Tins::EthernetII("ff:ff:ff:ff:ff:ff", info.hw_addr);
    //Set L2 Ethernet Packet as Broadcast Packet
 
    Tins::ARP testARP = Tins::ARP(target, info.ip_addr, "00:00:00:00:00:00", info.hw_addr);
    //Setup L3 ARP Packet (target_ip, sender_ip, target_hw, sender_hw)
 
    testARP.opcode(Tins::ARP::Flags::REQUEST);
    //Set ARP flag as Request
 
    eth /= testARP;
    //Build-up ARP Protocol on Ethernet
 
    printf("Send!\n");
    sender.send(eth, iface);
    //Send Packet
    return 0;
}
 
 
cs

Source Code


Request Packet (Crafted by libtins)


Reply Packet (Android Nexus5x)




[ICMP]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <tins/tins.h>
#include <unistd.h>
 
int main()
{
    Tins::PacketSender sender;
    //Libtins packetsender(Virtual L1 Physical Layer)
 
    Tins::IPv4Address target = Tins::IPv4Address("192.168.43.1");
    //Target IP
 
    Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
    Tins::NetworkInterface::Info info = iface.addresses();
    //Get addresses from network interface
 
    Tins::EthernetII eth = Tins::EthernetII("ff:ff:ff:ff:ff:ff", info.hw_addr);
    //Set L2 Ethernet Packet as Broadcast Packet
 
    Tins::IP ip = Tins::IP(target, info.ip_addr);
    ip.protocol(Tins::IP::ICMP);
    //Set L3 IPv4 Packet
 
    Tins::ICMP testICMP = Tins::ICMP();
    testICMP.code(Tins::ICMP::ECHO_REQUEST);
    //Set L3 ICMP Packet as ECHO_REQUEST Packet
 
    eth /= ip;
    eth /= testICMP;
    //Build-up IPv4&ICMP Protocol
 
    printf("Send!\n");
    sender.send(eth, iface);
    //Send Packet
    return 0;
}
 
 
cs

Source Code

Request Packet (Crafted by libtins)


Reply Packet (Android Nexus5x)



'Network' 카테고리의 다른 글

[Network/libtins] Wi-Fi auto deauthentication attack (C++)  (0) 2016.06.27
[Network/ARP] ARP Request/Reply  (0) 2016.06.25
[Network/Ethernet] EthernetII header  (0) 2016.06.21
Posted by RevDev
,

-Callback implementation with STL (Modern C++)-



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "global.h"
#include "core/interface.h"
 
typedef std::function<void()> Callback;
 
int main(int argc, char** argv)
{
    std::map<std::string, Callback> mapCallback;
    mapCallback.insert(std::pair<std::string, Callback>("open"std::bind(MainInterface::setupUnkFile)));
    mapCallback.insert(std::pair<std::string, Callback>("procview"std::bind(MainInterface::logviewCurrentProc)));
    mapCallback.insert(std::pair<std::string, Callback>("history"std::bind(MainInterface::logviewHistoryProc)));
    mapCallback.insert(std::pair<std::string, Callback>("vmstatus"std::bind(MainInterface::logviewCurrentStat)));
    mapCallback.insert(std::pair<std::string, Callback>("procmgr"std::bind(MainInterface::ctrlProcMgr)));
    mapCallback.insert(std::pair<std::string, Callback>("imexport"std::bind(MainInterface::ctrlImExport)));
    mapCallback.insert(std::pair<std::string, Callback>("exit"std::bind([](){std::exit(0);})));
 
    if (argc > 1)
    {
        std::string strArgv = argv[1];
        auto it = mapCallback.find(strArgv);
        if (it != mapCallback.end())
            it->second();
    }
 
    else MainInterface::setupInterface();
}
 
cs



Posted by RevDev
,