req.c 6.8 KB
Newer Older
K
Kozlov Dmitry 已提交
1
#include <stdlib.h>
2
#include <stdio.h>
D
Dmitry Kozlov 已提交
3 4 5 6
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
K
Kozlov Dmitry 已提交
7
#include <sched.h>
D
Dmitry Kozlov 已提交
8 9 10
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
K
Kozlov Dmitry 已提交
11

D
Dmitry Kozlov 已提交
12
#include "log.h"
13
#include "radius_p.h"
K
Kozlov Dmitry 已提交
14

D
Dmitry Kozlov 已提交
15 16
#include "memdebug.h"

17
static int urandom_fd;
K
Kozlov Dmitry 已提交
18 19

static int rad_req_read(struct triton_md_handler_t *h);
D
Dmitry Kozlov 已提交
20
static void rad_req_timeout(struct triton_timer_t *t);
K
Kozlov Dmitry 已提交
21

22
struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
K
Kozlov Dmitry 已提交
23
{
K
Kozlov Dmitry 已提交
24
	struct rad_plugin_t *plugin;
D
Dmitry Kozlov 已提交
25
	struct rad_req_t *req = _malloc(sizeof(*req));
K
Kozlov Dmitry 已提交
26 27 28 29 30 31 32

	if (!req)
		return NULL;

	memset(req, 0, sizeof(*req));
	req->rpd = rpd;
	req->hnd.fd = -1;
33
	req->ctx.before_switch = log_switch;
34

35
	req->server_addr = conf_auth_server;
36
	req->server_port = conf_auth_server_port;
K
Kozlov Dmitry 已提交
37

38 39 40 41
	while (1) {
		if (read(urandom_fd, req->RA, 16) != 16) {
			if (errno == EINTR)
				continue;
42
			log_ppp_error("radius:req:read urandom: %s\n", strerror(errno));
43 44 45 46 47 48 49 50 51
			goto out_err;
		}
		break;
	}

	req->pack = rad_packet_alloc(code);
	if (!req->pack)
		goto out_err;

K
Kozlov Dmitry 已提交
52
	if (rad_packet_add_str(req->pack, NULL, "User-Name", username))
K
Kozlov Dmitry 已提交
53 54
		goto out_err;
	if (conf_nas_identifier)
K
Kozlov Dmitry 已提交
55
		if (rad_packet_add_str(req->pack, NULL, "NAS-Identifier", conf_nas_identifier))
K
Kozlov Dmitry 已提交
56
			goto out_err;
57
	if (conf_nas_ip_address)
K
Kozlov Dmitry 已提交
58
		if (rad_packet_add_ipaddr(req->pack, NULL, "NAS-IP-Address", conf_nas_ip_address))
59
			goto out_err;
K
Kozlov Dmitry 已提交
60
	if (rad_packet_add_int(req->pack, NULL, "NAS-Port", rpd->ppp->unit_idx))
K
Kozlov Dmitry 已提交
61
		goto out_err;
K
Kozlov Dmitry 已提交
62
	if (rad_packet_add_val(req->pack, NULL, "NAS-Port-Type", "Virtual"))
K
Kozlov Dmitry 已提交
63
		goto out_err;
K
Kozlov Dmitry 已提交
64
	if (rad_packet_add_val(req->pack, NULL, "Service-Type", "Framed-User"))
K
Kozlov Dmitry 已提交
65
		goto out_err;
K
Kozlov Dmitry 已提交
66
	if (rad_packet_add_val(req->pack, NULL, "Framed-Protocol", "PPP"))
K
Kozlov Dmitry 已提交
67
		goto out_err;
68
	if (rpd->ppp->ctrl->calling_station_id)
K
Kozlov Dmitry 已提交
69
		if (rad_packet_add_str(req->pack, NULL, "Calling-Station-Id", rpd->ppp->ctrl->calling_station_id))
70 71
			goto out_err;
	if (rpd->ppp->ctrl->called_station_id)
K
Kozlov Dmitry 已提交
72
		if (rad_packet_add_str(req->pack, NULL, "Called-Station-Id", rpd->ppp->ctrl->called_station_id))
73
			goto out_err;
74
	if (rpd->attr_class)
K
Kozlov Dmitry 已提交
75
		if (rad_packet_add_octets(req->pack, NULL, "Class", rpd->attr_class, rpd->attr_class_len))
76
			goto out_err;
K
Kozlov Dmitry 已提交
77

K
Kozlov Dmitry 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90
	list_for_each_entry(plugin, &req->rpd->plugin_list, entry) {
		switch (code) {
			case CODE_ACCESS_REQUEST:
				if (plugin->send_access_request && plugin->send_access_request(plugin, req->pack))
					goto out_err;
				break;
			case CODE_ACCOUNTING_REQUEST:
				if (plugin->send_accounting_request && plugin->send_accounting_request(plugin, req->pack))
					goto out_err;
				break;
		}
	}

K
Kozlov Dmitry 已提交
91
	return req;
D
Dmitry Kozlov 已提交
92 93 94 95

out_err:
	rad_req_free(req);
	return NULL;
K
Kozlov Dmitry 已提交
96 97
}

98 99
int rad_req_acct_fill(struct rad_req_t *req)
{
100
	req->server_addr = conf_acct_server;
101 102 103 104
	req->server_port = conf_acct_server_port;

	memset(req->RA, 0, sizeof(req->RA));

K
Kozlov Dmitry 已提交
105
	if (rad_packet_add_val(req->pack, NULL, "Acct-Status-Type", "Start"))
106
		return -1;
K
Kozlov Dmitry 已提交
107
	if (rad_packet_add_val(req->pack, NULL, "Acct-Authentic", "RADIUS"))
108
		return -1;
K
Kozlov Dmitry 已提交
109
	if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", req->rpd->ppp->sessionid))
110
		return -1;
K
Kozlov Dmitry 已提交
111
	if (rad_packet_add_int(req->pack, NULL, "Acct-Session-Time", 0))
112
		return -1;
K
Kozlov Dmitry 已提交
113
	if (rad_packet_add_int(req->pack, NULL, "Acct-Input-Octets", 0))
114
		return -1;
K
Kozlov Dmitry 已提交
115
	if (rad_packet_add_int(req->pack, NULL, "Acct-Output-Octets", 0))
116
		return -1;
K
Kozlov Dmitry 已提交
117
	if (rad_packet_add_int(req->pack, NULL, "Acct-Input-Packets", 0))
118
		return -1;
K
Kozlov Dmitry 已提交
119
	if (rad_packet_add_int(req->pack, NULL, "Acct-Output-Packets", 0))
120
		return -1;
K
Kozlov Dmitry 已提交
121
	if (rad_packet_add_int(req->pack, NULL, "Acct-Input-Gigawords", 0))
122
		return -1;
K
Kozlov Dmitry 已提交
123
	if (rad_packet_add_int(req->pack, NULL, "Acct-Output-Gigawords", 0))
124
		return -1;
K
Kozlov Dmitry 已提交
125
	if (rad_packet_add_int(req->pack, NULL, "Acct-Delay-Time", 0))
126
		return -1;
K
Kozlov Dmitry 已提交
127
	if (rad_packet_add_ipaddr(req->pack, NULL, "Framed-IP-Address", req->rpd->ppp->peer_ipaddr))
128
		return -1;
129 130 131 132

	return 0;
}

133
void rad_req_free(struct rad_req_t *req)
K
Kozlov Dmitry 已提交
134
{
135 136 137 138 139 140
	if (req->hnd.fd >= 0 )
		close(req->hnd.fd);
	if (req->pack)
		rad_packet_free(req->pack);
	if (req->reply)
		rad_packet_free(req->reply);
D
Dmitry Kozlov 已提交
141
	_free(req);
K
Kozlov Dmitry 已提交
142 143
}

144
static int make_socket(struct rad_req_t *req)
K
Kozlov Dmitry 已提交
145 146
{
  struct sockaddr_in addr;
147

148 149
	req->hnd.fd = socket(PF_INET, SOCK_DGRAM, 0);
	if (req->hnd.fd < 0) {
150
		log_ppp_error("radius:socket: %s\n", strerror(errno));
151 152
		return -1;
	}
K
Kozlov Dmitry 已提交
153

154 155
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
K
Kozlov Dmitry 已提交
156

K
Kozlov Dmitry 已提交
157 158
	if (conf_bind) {
		addr.sin_addr.s_addr = conf_bind;
159
		if (bind(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) {
160
			log_ppp_error("radius:bind: %s\n", strerror(errno));
K
Kozlov Dmitry 已提交
161 162
			goto out_err;
		}
163
	}
K
Kozlov Dmitry 已提交
164

165
	addr.sin_addr.s_addr = req->server_addr;
166
	addr.sin_port = htons(req->server_port);
K
Kozlov Dmitry 已提交
167

168
	if (connect(req->hnd.fd, (struct sockaddr *) &addr, sizeof(addr))) {
169
		log_ppp_error("radius:connect: %s\n", strerror(errno));
170 171 172 173
		goto out_err;
	}

	if (fcntl(req->hnd.fd, F_SETFL, O_NONBLOCK)) {
174
		log_ppp_error("radius: failed to set nonblocking mode: %s\n", strerror(errno));
175
		goto out_err;
K
Kozlov Dmitry 已提交
176 177
	}
	
178 179 180 181 182 183 184 185
	return 0;

out_err:
	close(req->hnd.fd);
	req->hnd.fd = -1;
	return -1;
}

186
int rad_req_send(struct rad_req_t *req, int verbose)
187 188 189 190 191 192 193
{
	if (req->hnd.fd == -1 && make_socket(req))
		return -1;

	if (!req->pack->buf && rad_packet_build(req->pack, req->RA))
		goto out_err;
	
194
	if (verbose) {
195 196
		log_ppp_info1("send ");
		rad_packet_print(req->pack, log_ppp_info1);
197 198
	}

199
	rad_packet_send(req->pack, req->hnd.fd, NULL);
K
Kozlov Dmitry 已提交
200 201 202 203 204 205 206 207 208

	return 0;

out_err:
	close(req->hnd.fd);
	req->hnd.fd = -1;
	return -1;
}

209 210
static void req_wakeup(struct rad_req_t *req)
{
211
	struct triton_context_t *ctx = req->rpd->ppp->ctrl->ctx;
K
Kozlov Dmitry 已提交
212 213
	if (req->timeout.tpd)
		triton_timer_del(&req->timeout);
214 215
	triton_md_unregister_handler(&req->hnd);
	triton_context_unregister(&req->ctx);
216
	triton_context_wakeup(ctx);
217
}
K
Kozlov Dmitry 已提交
218 219 220
static int rad_req_read(struct triton_md_handler_t *h)
{
	struct rad_req_t *req = container_of(h, typeof(*req), hnd);
K
Kozlov Dmitry 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
	struct rad_packet_t *pack;
	int r;

	while (1) {
		r = rad_packet_recv(h->fd, &pack, NULL);
		
		if (pack) {
			if (req->reply)
				rad_packet_free(req->reply);
			req->reply = pack;
		}

		if (r)
			break;
	}
K
Kozlov Dmitry 已提交
236

237 238
	req_wakeup(req);
	
D
Dmitry Kozlov 已提交
239
	return 1;
K
Kozlov Dmitry 已提交
240
}
D
Dmitry Kozlov 已提交
241
static void rad_req_timeout(struct triton_timer_t *t)
K
Kozlov Dmitry 已提交
242
{
243 244 245
	struct rad_req_t *req = container_of(t, typeof(*req), timeout);
	
	req_wakeup(req);
K
Kozlov Dmitry 已提交
246 247
}

D
Dmitry Kozlov 已提交
248
int rad_req_wait(struct rad_req_t *req, int timeout)
K
Kozlov Dmitry 已提交
249
{
250 251 252
	req->hnd.read = rad_req_read;
	req->timeout.expire = rad_req_timeout;

253
	triton_context_register(&req->ctx, req->rpd->ppp);
254
	triton_md_register_handler(&req->ctx, &req->hnd);
K
Kozlov Dmitry 已提交
255
	triton_md_enable_handler(&req->hnd, MD_MODE_READ);
K
Kozlov Dmitry 已提交
256

D
Dmitry Kozlov 已提交
257
	req->timeout.period = timeout * 1000;
K
Kozlov Dmitry 已提交
258 259 260
	triton_timer_add(&req->ctx, &req->timeout, 0);
	
	triton_context_wakeup(&req->ctx);
K
Kozlov Dmitry 已提交
261

262
	triton_context_schedule();
K
Kozlov Dmitry 已提交
263

264
	if (conf_verbose && req->reply) {
265 266
		log_ppp_info1("recv ");
		rad_packet_print(req->reply, log_ppp_info1);
267
	}
K
Kozlov Dmitry 已提交
268 269 270
	return 0;
}

271
static void req_init(void)
272 273 274
{
	urandom_fd = open("/dev/urandom", O_RDONLY);
	if (!urandom_fd) {
275
		log_emerg("radius:req: open /dev/urandom: %s\n", strerror(errno));
276 277 278
		_exit(EXIT_FAILURE);
	}
}
279

K
Kozlov Dmitry 已提交
280
DEFINE_INIT(50, req_init);