Coverage Report

Created: 2026-03-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/protocols/dhcpv4/dhcpv4.h
Line
Count
Source
1
#pragma once
2
/*
3
 *  This program is free software; you can redistribute it and/or modify
4
 *  it under the terms of the GNU General Public License as published by
5
 *  the Free Software Foundation; either version 2 of the License, or
6
 *  (at your option) any later version.
7
 *
8
 *  This program is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 *  GNU General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU General Public License
14
 *  along with this program; if not, write to the Free Software
15
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16
 */
17
18
/**
19
 * $Id: 72b9fa0a2af2f3ea07ceba51bed0329606b0cd27 $
20
 *
21
 * @file protocols/dhcpv4/dhcpv4.h
22
 * @brief Implementation of the DHCPv4 protocol.
23
 *
24
 * @copyright 2008 The FreeRADIUS server project
25
 * @copyright 2008 Alan DeKok (aland@deployingradius.com)
26
 */
27
RCSIDH(dhcp_h, "$Id: 72b9fa0a2af2f3ea07ceba51bed0329606b0cd27 $")
28
29
#ifdef __cplusplus
30
extern "C" {
31
#endif
32
33
#include <freeradius-devel/util/pcap.h>
34
#include <freeradius-devel/util/packet.h>
35
#include <freeradius-devel/protocol/dhcpv4/rfc2131.h>
36
37
#define DHCP_CHADDR_LEN (16)
38
78
#define DHCP_SNAME_LEN  (64)
39
133
#define DHCP_FILE_LEN (128)
40
#define DHCP_VEND_LEN (308)
41
0
#define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
42
43
typedef enum {
44
  FR_DHCP_INVALID = 0,
45
  FR_DHCP_DISCOVER = 1,
46
  FR_DHCP_OFFER = 2,
47
  FR_DHCP_REQUEST = 3,
48
  FR_DHCP_DECLINE = 4,
49
  FR_DHCP_ACK = 5,
50
  FR_DHCP_NAK = 6,
51
  FR_DHCP_RELEASE = 7,
52
  FR_DHCP_INFORM = 8,
53
  FR_DHCP_FORCE_RENEW = 9,
54
  FR_DHCP_LEASE_QUERY = 10,
55
  FR_DHCP_LEASE_UNASSIGNED = 11,
56
  FR_DHCP_LEASE_UNKNOWN = 12,
57
  FR_DHCP_LEASE_ACTIVE = 13,
58
  FR_DHCP_BULK_LEASE_QUERY = 14,
59
  FR_DHCP_LEASE_QUERY_DONE = 15,
60
  FR_DHCP_CODE_MAX = 16,
61
  FR_DHCP_DO_NOT_RESPOND = 256,
62
} fr_dhcpv4_packet_code_t;
63
64
#define FR_DHCP_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) < FR_DHCP_CODE_MAX))
65
66
typedef struct {
67
  uint8_t   opcode;
68
  uint8_t   htype;
69
  uint8_t   hlen;
70
  uint8_t   hops;
71
  uint32_t  xid;  /* 4 */
72
  uint16_t  secs; /* 8 */
73
  uint16_t  flags;
74
  uint32_t  ciaddr; /* 12 */
75
  uint32_t  yiaddr; /* 16 */
76
  uint32_t  siaddr; /* 20 */
77
  uint32_t  giaddr; /* 24 */
78
  uint8_t   chaddr[DHCP_CHADDR_LEN]; /* 28 */
79
  uint8_t   sname[DHCP_SNAME_LEN]; /* 44 */
80
  uint8_t   file[DHCP_FILE_LEN]; /* 108 */
81
  uint32_t  option_format; /* 236 */
82
  uint8_t   options[DHCP_VEND_LEN];
83
} dhcp_packet_t;
84
85
/*
86
 *  Some clients silently ignore responses less than 300 bytes.
87
 */
88
463
#define MIN_PACKET_SIZE   (244)
89
0
#define DEFAULT_PACKET_SIZE (300)
90
0
#define MAX_PACKET_SIZE   (1500 - 40)
91
#define DHCPV4_MAX_ATTRIBUTES 255
92
93
775
#define DHCP_OPTION_FIELD (0)
94
621
#define DHCP_FILE_FIELD     (1)
95
37
#define DHCP_SNAME_FIELD    (2)
96
97
#define DHCP_PACK_OPTION1(x,y) ((x) | ((y) << 8))
98
#define DHCP_UNPACK_OPTION1(x) (((x) & 0xff00) >> 8)
99
100
#ifndef INADDR_BROADCAST
101
#  define INADDR_BROADCAST INADDR_NONE
102
#endif
103
0
#define ETH_ADDR_LEN   6
104
105
#if defined(HAVE_LIBPCAP) || defined(HAVE_LINUX_IF_PACKET_H)
106
0
#  define ETH_TYPE_IP    0x0800
107
0
#  define IP_HDR_SIZE    20
108
0
#  define UDP_HDR_SIZE   8
109
#endif
110
111
extern fr_dict_attr_t const   **dhcp_header_attrs[];
112
extern size_t       dhcp_header_attrs_len;
113
extern char const     *dhcp_message_types[];
114
extern int        dhcp_header_sizes[];
115
extern uint8_t        eth_bcast[ETH_ADDR_LEN];
116
117
#ifdef HAVE_LINUX_IF_PACKET_H
118
0
#  define ETH_HDR_SIZE   14
119
/* Discard raw packets which we are not interested in. Allow to trace why we discard. */
120
0
#  define DISCARD_RP(...) { \
121
0
  if (fr_debug_lvl > 2) { \
122
0
    fprintf(stdout, "dhcpclient: discarding received packet: "); \
123
0
    fprintf(stdout, ## __VA_ARGS__); \
124
0
    fprintf(stdout, "\n"); \
125
0
  } \
126
0
  fr_packet_free(&packet); \
127
0
  return NULL; \
128
0
}
129
#endif
130
131
/** Used as the decoder ctx
132
 *
133
 */
134
typedef struct {
135
  fr_dict_attr_t const *root;
136
  TALLOC_CTX  *tmp_ctx;   //!< for temporary things cleaned up during decoding
137
} fr_dhcpv4_ctx_t;
138
139
typedef enum {
140
  DHCPV4_FLAG_PREFIX_INVALID = -1,
141
  DHCPV4_FLAG_PREFIX_NONE = 0,
142
  DHCPV4_FLAG_PREFIX_BITS = 1,
143
  DHCPV4_FLAG_PREFIX_SPLIT = 2,
144
} fr_dhcpv4_attr_flags_prefix_t;
145
146
typedef struct {
147
  bool        exists;
148
  bool        dns_label;
149
  fr_dhcpv4_attr_flags_prefix_t prefix;
150
} fr_dhcpv4_attr_flags_t;
151
152
static inline fr_dhcpv4_attr_flags_t const *fr_dhcpv4_attr_flags(fr_dict_attr_t const *da)
153
15.9k
{
154
15.9k
  return fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
155
15.9k
}
decode.c:fr_dhcpv4_attr_flags
Line
Count
Source
153
15.9k
{
154
15.9k
  return fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC);
155
15.9k
}
Unexecuted instantiation: encode.c:fr_dhcpv4_attr_flags
Unexecuted instantiation: packet.c:fr_dhcpv4_attr_flags
Unexecuted instantiation: raw.c:fr_dhcpv4_attr_flags
Unexecuted instantiation: udp.c:fr_dhcpv4_attr_flags
156
157
7.29k
#define fr_dhcpv4_flag_dns_label(_da)   (fr_dhcpv4_attr_flags(_da)->dns_label)
158
0
#define fr_dhcpv4_flag_exists(_da)    (fr_dhcpv4_attr_flags(_da)->exists)
159
160
#define fr_dhcpv4_flag_prefix(_da)    fr_dhcpv4_attr_flags(_da)->prefix
161
3.72k
#define fr_dhcpv4_flag_prefix_bits(_da)   (fr_dhcpv4_attr_flags(_da)->prefix == DHCPV4_FLAG_PREFIX_BITS)
162
4.94k
#define fr_dhcpv4_flag_prefix_split(_da)  (fr_dhcpv4_attr_flags(_da)->prefix == DHCPV4_FLAG_PREFIX_SPLIT)
163
164
/*
165
 *  base.c
166
 */
167
int8_t    fr_dhcpv4_attr_cmp(void const *a, void const *b);
168
169
bool    fr_dhcpv4_ok(uint8_t const *data, ssize_t data_len, uint8_t *message_type, uint32_t *xid);
170
fr_packet_t *fr_dhcpv4_packet_alloc(uint8_t const *data, size_t data_len);
171
bool    fr_dhcpv4_is_encodable(void const *item, void const *uctx);
172
void    *fr_dhcpv4_next_encodable(fr_dcursor_t *cursor, void *to_eval, void *uctx);
173
ssize_t   fr_dhcpv4_encode(uint8_t *buffer, size_t buflen, dhcp_packet_t *original, int code, uint32_t xid, fr_pair_list_t *vps);
174
ssize_t   fr_dhcpv4_encode_dbuff(fr_dbuff_t *dbuff, dhcp_packet_t *original, int code, uint32_t xid, fr_pair_list_t *vps);
175
ssize_t   fr_dhcpv4_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list);
176
int   fr_dhcpv4_global_init(void);
177
void    fr_dhcpv4_global_free(void);
178
void    fr_dhcpv4_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len);
179
180
/*
181
 *  decode.c
182
 */
183
ssize_t   fr_dhcpv4_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
184
          uint8_t const *data, size_t len, void *decode_ctx) CC_HINT(nonnull);
185
186
ssize_t   fr_dhcpv4_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out,
187
           uint8_t const *data, size_t data_len) CC_HINT(nonnull);
188
189
/*
190
 *  encode.c
191
 */
192
ssize_t   fr_dhcpv4_encode_option(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx);
193
194
/*
195
 *  packet.c
196
 */
197
uint8_t const *fr_dhcpv4_packet_get_option(dhcp_packet_t const *packet, size_t packet_size, fr_dict_attr_t const *da);
198
199
int   fr_dhcpv4_decode(TALLOC_CTX *ctx, fr_pair_list_t *out,
200
         uint8_t const *data, size_t data_len, unsigned int *code);
201
202
int   fr_dhcpv4_packet_encode(fr_packet_t *packet, fr_pair_list_t *list);
203
204
#ifdef HAVE_LINUX_IF_PACKET_H
205
/*
206
 *  raw.c
207
 */
208
#include <linux/if_packet.h>
209
int   fr_dhcpv4_raw_socket_open(struct sockaddr_ll *p_ll, int iface_index);
210
211
int   fr_dhcpv4_raw_packet_send(int sockfd, struct sockaddr_ll *p_ll,
212
            fr_packet_t *packet, fr_pair_list_t *list);
213
214
fr_packet_t *fr_dhcpv4_raw_packet_recv(int sockfd, struct sockaddr_ll *p_ll,
215
              fr_packet_t *request, fr_pair_list_t *list);
216
#endif
217
218
/*
219
 *  pcap.c
220
 */
221
#ifdef HAVE_LIBPCAP
222
/*
223
 *  Use fr_pcap_init and fr_pcap_open to create/open handles.
224
 */
225
fr_packet_t *fr_dhcpv4_pcap_recv(fr_pcap_t *pcap);
226
227
int   fr_dhcpv4_pcap_send(fr_pcap_t *pcap, uint8_t *dst_ether_addr, fr_packet_t *packet);
228
#endif
229
230
/*
231
 *  udp.c
232
 */
233
fr_packet_t *fr_dhcpv4_udp_packet_recv(int sockfd);
234
int   fr_dhcpv4_udp_packet_send(fr_packet_t *packet);
235
236
#ifdef __cplusplus
237
}
238
#endif