embox

Форк
0
/
raw_sock.c 
219 строк · 5.3 Кб
1
/**
2
 * @file
3
 * @brief Implements raw socket function.
4
 *
5
 * @date 04.02.10
6
 * @author Anton Bondarev
7
 * @author Ilia Vaprol
8
 */
9

10
#include <assert.h>
11
#include <stddef.h>
12
#include <string.h>
13
#include <sys/socket.h>
14
#include <errno.h>
15
#include <netinet/in.h>
16

17
#include <net/l3/ipv4/ip.h>
18
#include <net/l3/icmpv4.h>
19
#include <net/skbuff.h>
20
#include <net/sock.h>
21
#include <net/socket/inet_sock.h>
22
#include <net/socket/raw.h>
23
#include <net/netdevice.h>
24

25
#include <lib/libds/dlist.h>
26

27
#include "net_sock.h"
28
#include <embox/net/pack.h>
29

30
static const struct sock_proto_ops raw_sock_ops_struct;
31
const struct sock_proto_ops *const raw_sock_ops
32
		= &raw_sock_ops_struct;
33

34
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0,
35
		raw_sock_ops_struct);
36
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_UDP, 0,
37
		raw_sock_ops_struct);
38
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_TCP, 0,
39
		raw_sock_ops_struct);
40
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_RAW, 0,
41
		raw_sock_ops_struct);
42

43
static int raw_rcv_tester(const struct sock *sk,
44
		const struct sk_buff *skb) {
45
	const struct inet_sock *in_sk;
46

47
	in_sk = (const struct inet_sock *)sk;
48
	assert(in_sk != NULL);
49
	assert(in_sk->src_in.sin_family == AF_INET);
50
	assert(in_sk->dst_in.sin_family == AF_INET);
51

52
	assert(skb != NULL);
53
	assert(skb->nh.iph != NULL);
54

55
	return ((in_sk->src_in.sin_addr.s_addr == skb->nh.iph->daddr)
56
				|| (in_sk->src_in.sin_addr.s_addr == INADDR_ANY))
57
			&& ((in_sk->dst_in.sin_addr.s_addr == skb->nh.iph->saddr)
58
				|| (in_sk->dst_in.sin_addr.s_addr == INADDR_ANY))
59
			&& (in_sk->sk.opt.so_protocol == skb->nh.iph->proto)
60
			&& ((in_sk->sk.opt.so_bindtodevice == skb->dev)
61
				|| (in_sk->sk.opt.so_bindtodevice == NULL));
62
}
63

64
extern uint16_t skb_get_secure_level(const struct sk_buff *skb);
65
extern uint16_t sock_get_secure_level(const struct sock *sk);
66

67
int raw_rcv(const struct sk_buff *skb) {
68
	struct sock *sk;
69
	struct sk_buff *cloned;
70

71
	assert(skb != NULL);
72
	assert(skb->dev != NULL);
73

74
	sk = NULL;
75

76
	while (1) {
77

78
		sk = sock_lookup(sk, raw_sock_ops, raw_rcv_tester, skb);
79
		if (sk == NULL) {
80
			break;
81
		}
82
		/* if we have socket with secure label we have to check secure level */
83
		if (sock_get_secure_level(sk) >	skb_get_secure_level(skb)) {
84
			return 0;
85
		}
86

87
		cloned = skb_clone(skb);
88
		if (cloned == NULL) {
89
			return -ENOMEM;
90
		}
91

92
		sock_rcv(sk, cloned, cloned->nh.raw,
93
				cloned->len - skb->dev->hdr_len);
94
	}
95

96
	return 0;
97
}
98

99
static int raw_err_tester(const struct sock *sk,
100
		const struct sk_buff *skb) {
101
	const struct inet_sock *in_sk;
102
	const struct iphdr *emb_pack_iphdr;
103

104
	in_sk = (const struct inet_sock *)sk;
105
	assert(in_sk != NULL);
106
	assert(in_sk->src_in.sin_family == AF_INET);
107
	assert(in_sk->dst_in.sin_family == AF_INET);
108

109
	assert(skb != NULL);
110
	assert(skb->h.raw != NULL);
111
	emb_pack_iphdr = (const struct iphdr *)(skb->h.raw
112
			+ IP_HEADER_SIZE(skb->nh.iph) + ICMP_MIN_HEADER_SIZE);
113

114
	return (((in_sk->src_in.sin_addr.s_addr == skb->nh.iph->daddr)
115
					&& (in_sk->src_in.sin_addr.s_addr == emb_pack_iphdr->saddr))
116
				|| (in_sk->src_in.sin_addr.s_addr == INADDR_ANY))
117
			&& (((in_sk->dst_in.sin_addr.s_addr == skb->nh.iph->saddr)
118
					&& (in_sk->dst_in.sin_addr.s_addr == emb_pack_iphdr->daddr))
119
				|| (in_sk->dst_in.sin_addr.s_addr == INADDR_ANY))
120
			&& (in_sk->sk.opt.so_protocol == skb->nh.iph->proto)
121
			&& ((in_sk->sk.opt.so_bindtodevice == skb->dev)
122
				|| (in_sk->sk.opt.so_bindtodevice == NULL));
123
}
124

125
void raw_err(const struct sk_buff *skb, int error_info) {
126
	struct sock *sk;
127

128
	sk = NULL;
129

130
	while (1) {
131
		sk = sock_lookup(sk, raw_sock_ops, raw_err_tester, skb);
132
		if (sk == NULL) {
133
			break;
134
		}
135

136
		sock_set_so_error(sk, error_info);
137
	}
138
}
139

140
static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int flags) {
141
	int ret;
142
	size_t data_len;
143
	struct sk_buff *skb;
144
	const struct sockaddr *sockaddr;
145
	int fill_iphdr = 1;
146

147
	assert(sk);
148
	assert(msg);
149
	assert(msg->msg_iov);
150
	assert(msg->msg_iov->iov_base);
151
	assert(sk->o_ops);
152
	assert(sk->o_ops->make_pack);
153

154
	data_len = msg->msg_iov->iov_len;
155
	skb = NULL;
156
	sockaddr = (const struct sockaddr *)msg->msg_name;
157

158
	if (sk->opt.so_type == SOCK_RAW) {
159
		struct inet_sock *inet = to_inet_sock(sk);
160

161
		if (sk->opt.so_protocol == IPPROTO_RAW) {
162
			/* It is Linux specific behaviour. FreeBSD does not set this flag by default
163
			 * when protocol is IPPROTO_RAW.
164
			 * See http://sock-raw.org/papers/sock_raw */
165
			inet->opt.hdrincl = 1;
166
		}
167

168
		if (inet->opt.hdrincl) {
169
			fill_iphdr = 0;
170
		}
171
	}
172

173
	if (fill_iphdr) {
174
		ret = sk->o_ops->make_pack(sk, sockaddr, &data_len, &skb);
175
	} else {
176
		size_t actual_data_len;
177
		if (data_len < sizeof(struct iphdr)) {
178
			return -EMSGSIZE;
179
		}
180
		actual_data_len = data_len - sizeof(struct iphdr);
181
		ret = sk->o_ops->make_pack(sk, sockaddr, &actual_data_len, &skb);
182
		data_len = actual_data_len + sizeof(struct iphdr);
183
	}
184

185
	if (ret != 0) {
186
		return ret;
187
	}
188

189
	if (data_len < msg->msg_iov->iov_len) {
190
		skb_free(skb);
191
		return -EMSGSIZE;
192
	}
193

194
	assert(sk);
195
	assert(skb->h.raw);
196

197
	if (fill_iphdr) {
198
		memcpy(skb->h.raw, msg->msg_iov->iov_base, data_len);
199
	} else {
200
		/* Rewrite IP header made by sk->o_ops->make_pack above +
201
		 * write @c actual_data_len payload */
202
		memcpy(skb->nh.raw, msg->msg_iov->iov_base, data_len);
203
	}
204

205
	assert(sk->o_ops->snd_pack != NULL);
206
	ret = sk->o_ops->snd_pack(skb);
207
	if (0 > ret) {
208
		return ret;
209
	}
210
	return data_len;
211
}
212

213
static DLIST_DEFINE(raw_sock_list);
214

215
static const struct sock_proto_ops raw_sock_ops_struct = {
216
	.sendmsg   = raw_sendmsg,
217
	.recvmsg   = sock_dgram_recvmsg,
218
	.sock_list = &raw_sock_list
219
};
220

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.