Integrate more into the server. Dp4
[freeradius.git] / src / main / dhcpd.c
1 /*
2  * dhcp.c       DHCP processing.  Done poorly for now.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008 Alan DeKok <aland@deployingradius.com>
22  */
23
24 #ifdef WITH_DHCP
25
26 static int dhcp_process(REQUEST *request)
27 {
28         int rcode;
29         VALUE_PAIR *vp;
30
31         vp = pairfind(request->packet->vps, DHCP2ATTR(53)); /* DHCP-Message-Type */
32         if (vp) {
33                 DICT_VALUE *dv = dict_valbyattr(DHCP2ATTR(53), vp->vp_integer);
34                 DEBUG("Trying sub-section dhcp %s {...}",
35                       dv->name ? dv->name : "<unknown>");
36                 rcode = module_post_auth(vp->vp_integer, request);
37         } else {
38                 DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
39                 rcode = RLM_MODULE_FAIL;
40         }
41
42         /*
43          *      Look for Relay attribute, and forward it if so...
44          */
45
46         switch (rcode) {
47         case RLM_MODULE_OK:
48         case RLM_MODULE_UPDATED:
49                 if (request->packet->code == (PW_DHCP_DISCOVER)) {
50                         request->reply->code = PW_DHCP_OFFER;
51                         break;
52
53                 } else if (request->packet->code == PW_DHCP_REQUEST) {
54                         request->reply->code = PW_DHCP_ACK;
55                         break;
56                 }
57
58                 /* FALL-THROUGH */
59
60         default:
61         case RLM_MODULE_REJECT:
62         case RLM_MODULE_FAIL:
63         case RLM_MODULE_INVALID:
64         case RLM_MODULE_NOOP:
65                 request->reply->code = PW_DHCP_NAK;
66                 break;
67
68         case RLM_MODULE_NOTFOUND:
69                 request->reply->code = PW_DHCP_DECLINE;
70                 break;
71
72         case RLM_MODULE_HANDLED:
73                 request->reply->code = PW_DHCP_NAK;
74                 break;
75         }
76
77         return 1;
78 }
79
80 static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
81 {
82         int rcode;
83         int on = 1;
84         listen_socket_t *sock;
85
86         rcode = common_socket_parse(cs, this);
87         if (rcode != 0) return rcode;
88
89         sock = this->data;
90
91         /*
92          *      FIXME: Parse config file option for "do broadast = yes/no"
93          */
94         if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
95                 radlog(L_ERR, "Can't set broadcast option: %s\n",
96                        strerror(errno));
97                 return -1;
98         }
99
100         if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
101                 radlog(L_ERR, "Can't set re-use addres option: %s\n",
102                        strerror(errno));
103                 return -1;
104         }
105
106         return 0;
107 }
108
109
110 /*
111  *      Check if an incoming request is "ok"
112  *
113  *      It takes packets, not requests.  It sees if the packet looks
114  *      OK.  If so, it does a number of sanity checks on it.
115  */
116 static int dhcp_socket_recv(rad_listen_t *listener,
117                             RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
118 {
119         RADIUS_PACKET   *packet;
120         RADCLIENT       *client;
121
122         packet = fr_dhcp_recv(listener->fd);
123         if (!packet) {
124                 radlog(L_ERR, "%s", librad_errstr);
125                 return 0;
126         }
127
128         if ((client = client_listener_find(listener,
129                                            &packet->src_ipaddr)) == NULL) {
130                 char buffer[256];
131                 radlog(L_ERR, "Ignoring request from unknown client %s port %d",
132                        inet_ntop(packet->src_ipaddr.af,
133                                  &packet->src_ipaddr.ipaddr,
134                                  buffer, sizeof(buffer)),
135                        packet->src_port);
136                 rad_free(&packet);
137                 return 0;
138         }
139
140         if (!received_request(listener, packet, prequest, client)) {
141                 rad_free(&packet);
142                 return 0;
143         }
144
145         *pfun = dhcp_process;
146
147         return 1;
148 }
149
150
151 /*
152  *      Send an authentication response packet
153  */
154 static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
155 {
156         rad_assert(request->listener == listener);
157         rad_assert(listener->send == dhcp_socket_send);
158
159         if (request->reply->code == 0) return 0; /* don't reply */
160
161         if (fr_dhcp_encode(request->reply, request->packet) < 0) {
162                 return -1;
163         }
164
165         return fr_dhcp_send(request->reply);
166 }
167
168
169 static int dhcp_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
170 {
171         DEBUG2("NO ENCODE!");
172         return 0;
173         return fr_dhcp_encode(request->reply, request->packet);
174 }
175
176
177 static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
178 {
179         return fr_dhcp_decode(request->packet);
180 }
181 #endif /* WITH_DCHP */
182