udhcpc6: new applet. Not yet functional.
It builds. It sends Solicit packets. Not sure these packets are well-formed. I have no server to test it against. function old new delta udhcpc6_main - 2426 +2426 d6_send_raw_packet - 428 +428 d6_send_kernel_packet - 274 +274 d6_recv_raw_packet - 248 +248 send_d6_discover - 177 +177 packed_usage 28795 28966 +171 d6_run_script - 156 +156 send_d6_renew - 140 +140 send_d6_release - 126 +126 d6_recv_kernel_packet - 116 +116 send_d6_select - 95 +95 perform_d6_release - 78 +78 d6_find_option - 74 +74 init_d6_packet - 54 +54 d6_copy_option - 48 +48 d6_mcast_from_client_config_ifindex - 42 +42 d6_dump_packet - 24 +24 static.FF02__1_2 - 16 +16 d6_store_blob - 13 +13 applet_names 2432 2440 +8 applet_main 1412 1416 +4 applet_nameofs 706 708 +2 add_d6_client_options - 1 +1 ------------------------------------------------------------------------------ (add/remove: 21/0 grow/shrink: 4/0 up/down: 4721/0) Total: 4721 bytes text data bss dec hex filename 879080 493 7584 887157 d8975 busybox_old 884585 497 7584 892666 d9efa busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
50089fc61c
commit
9ba75048c0
118
networking/udhcp/d6_common.h
Normal file
118
networking/udhcp/d6_common.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2011 Denys Vlasenko.
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#ifndef UDHCP_D6_COMMON_H
|
||||
#define UDHCP_D6_COMMON_H 1
|
||||
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
|
||||
|
||||
|
||||
/*** DHCPv6 packet ***/
|
||||
|
||||
/* DHCPv6 protocol. See RFC 3315 */
|
||||
#define D6_MSG_SOLICIT 1
|
||||
#define D6_MSG_ADVERTISE 2
|
||||
#define D6_MSG_REQUEST 3
|
||||
#define D6_MSG_CONFIRM 4
|
||||
#define D6_MSG_RENEW 5
|
||||
#define D6_MSG_REBIND 6
|
||||
#define D6_MSG_REPLY 7
|
||||
#define D6_MSG_RELEASE 8
|
||||
#define D6_MSG_DECLINE 9
|
||||
#define D6_MSG_RECONFIGURE 10
|
||||
#define D6_MSG_INFORMATION_REQUEST 11
|
||||
#define D6_MSG_RELAY_FORW 12
|
||||
#define D6_MSG_RELAY_REPL 13
|
||||
|
||||
struct d6_packet {
|
||||
union {
|
||||
uint8_t d6_msg_type;
|
||||
uint32_t d6_xid32;
|
||||
} d6_u;
|
||||
uint8_t d6_options[576 - sizeof(struct iphdr) - sizeof(struct udphdr) - 4
|
||||
+ CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
|
||||
} PACKED;
|
||||
#define d6_msg_type d6_u.d6_msg_type
|
||||
#define d6_xid32 d6_u.d6_xid32
|
||||
|
||||
struct ip6_udp_d6_packet {
|
||||
struct ip6_hdr ip6;
|
||||
struct udphdr udp;
|
||||
struct d6_packet data;
|
||||
} PACKED;
|
||||
|
||||
struct udp_d6_packet {
|
||||
struct udphdr udp;
|
||||
struct d6_packet data;
|
||||
} PACKED;
|
||||
|
||||
/*** Options ***/
|
||||
|
||||
struct d6_option {
|
||||
uint8_t code;
|
||||
uint8_t code_hi;
|
||||
uint8_t len;
|
||||
uint8_t len_hi;
|
||||
uint8_t data[1];
|
||||
} PACKED;
|
||||
|
||||
#define D6_OPT_CLIENTID 1
|
||||
#define D6_OPT_SERVERID 2
|
||||
#define D6_OPT_IA_NA 3
|
||||
#define D6_OPT_IA_TA 4
|
||||
#define D6_OPT_IAADDR 5
|
||||
#define D6_OPT_ORO 6
|
||||
#define D6_OPT_PREFERENCE 7
|
||||
#define D6_OPT_ELAPSED_TIME 8
|
||||
#define D6_OPT_RELAY_MSG 9
|
||||
#define D6_OPT_AUTH 11
|
||||
#define D6_OPT_UNICAST 12
|
||||
#define D6_OPT_STATUS_CODE 13
|
||||
#define D6_OPT_RAPID_COMMIT 14
|
||||
#define D6_OPT_USER_CLASS 15
|
||||
#define D6_OPT_VENDOR_CLASS 16
|
||||
#define D6_OPT_VENDOR_OPTS 17
|
||||
#define D6_OPT_INTERFACE_ID 18
|
||||
#define D6_OPT_RECONF_MSG 19
|
||||
#define D6_OPT_RECONF_ACCEPT 20
|
||||
|
||||
/*** Other shared functions ***/
|
||||
|
||||
struct client6_data_t {
|
||||
struct d6_option *server_id;
|
||||
struct d6_option *ia_na;
|
||||
};
|
||||
|
||||
#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)]))
|
||||
|
||||
int FAST_FUNC d6_listen_socket(int port, const char *inf);
|
||||
|
||||
int FAST_FUNC d6_recv_kernel_packet(
|
||||
struct in6_addr *peer_ipv6,
|
||||
struct d6_packet *packet, int fd
|
||||
);
|
||||
|
||||
int FAST_FUNC d6_send_raw_packet(
|
||||
struct d6_packet *d6_pkt, unsigned d6_pkt_size,
|
||||
struct in6_addr *src_ipv6, int source_port,
|
||||
struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp,
|
||||
int ifindex
|
||||
);
|
||||
|
||||
int FAST_FUNC d6_send_kernel_packet(
|
||||
struct d6_packet *d6_pkt, unsigned d6_pkt_size,
|
||||
struct in6_addr *src_ipv6, int source_port,
|
||||
struct in6_addr *dst_ipv6, int dest_port
|
||||
);
|
||||
|
||||
void FAST_FUNC d6_dump_packet(struct d6_packet *packet);
|
||||
|
||||
|
||||
POP_SAVED_FUNCTION_VISIBILITY
|
||||
|
||||
#endif
|
1404
networking/udhcp/d6_dhcpc.c
Normal file
1404
networking/udhcp/d6_dhcpc.c
Normal file
File diff suppressed because it is too large
Load Diff
168
networking/udhcp/d6_packet.c
Normal file
168
networking/udhcp/d6_packet.c
Normal file
@ -0,0 +1,168 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2011 Denys Vlasenko.
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "d6_common.h"
|
||||
#include "dhcpd.h"
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netpacket/packet.h>
|
||||
|
||||
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
|
||||
void FAST_FUNC d6_dump_packet(struct d6_packet *packet)
|
||||
{
|
||||
if (dhcp_verbose < 2)
|
||||
return;
|
||||
|
||||
bb_info_msg(
|
||||
" xid %x"
|
||||
, packet->d6_xid32
|
||||
);
|
||||
//*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
|
||||
//bb_info_msg(" chaddr %s", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6
|
||||
UNUSED_PARAM
|
||||
, struct d6_packet *packet, int fd)
|
||||
{
|
||||
int bytes;
|
||||
|
||||
memset(packet, 0, sizeof(*packet));
|
||||
bytes = safe_read(fd, packet, sizeof(*packet));
|
||||
if (bytes < 0) {
|
||||
log1("Packet read error, ignoring");
|
||||
return bytes; /* returns -1 */
|
||||
}
|
||||
|
||||
if (bytes < offsetof(struct d6_packet, d6_options)) {
|
||||
bb_info_msg("Packet with bad magic, ignoring");
|
||||
return -2;
|
||||
}
|
||||
log1("Received a packet");
|
||||
d6_dump_packet(packet);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* Construct a ipv6+udp header for a packet, send packet */
|
||||
int FAST_FUNC d6_send_raw_packet(
|
||||
struct d6_packet *d6_pkt, unsigned d6_pkt_size,
|
||||
struct in6_addr *src_ipv6, int source_port,
|
||||
struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp,
|
||||
int ifindex)
|
||||
{
|
||||
struct sockaddr_ll dest_sll;
|
||||
struct ip6_udp_d6_packet packet;
|
||||
int fd;
|
||||
int result = -1;
|
||||
const char *msg;
|
||||
|
||||
fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
|
||||
if (fd < 0) {
|
||||
msg = "socket(%s)";
|
||||
goto ret_msg;
|
||||
}
|
||||
|
||||
memset(&dest_sll, 0, sizeof(dest_sll));
|
||||
memset(&packet, 0, offsetof(struct ip6_udp_d6_packet, data));
|
||||
packet.data = *d6_pkt; /* struct copy */
|
||||
|
||||
dest_sll.sll_family = AF_PACKET;
|
||||
dest_sll.sll_protocol = htons(ETH_P_IPV6);
|
||||
dest_sll.sll_ifindex = ifindex;
|
||||
dest_sll.sll_halen = 6;
|
||||
memcpy(dest_sll.sll_addr, dest_arp, 6);
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
|
||||
msg = "bind(%s)";
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
packet.ip6.ip6_vfc = (6 << 4); /* 4 bits version, top 4 bits of tclass */
|
||||
if (src_ipv6)
|
||||
packet.ip6.ip6_src = *src_ipv6; /* struct copy */
|
||||
packet.ip6.ip6_dst = *dst_ipv6; /* struct copy */
|
||||
packet.udp.source = htons(source_port);
|
||||
packet.udp.dest = htons(dest_port);
|
||||
/* size, excluding IP header: */
|
||||
packet.udp.len = htons(sizeof(struct udphdr) + d6_pkt_size);
|
||||
packet.ip6.ip6_plen = packet.udp.len;
|
||||
/* UDP checksum skips first four bytes of IP header.
|
||||
* IPv6 'hop limit' field should be 0.
|
||||
* 'next header' field should be summed as if it is in a different
|
||||
* position, therefore we write its value into ip6_hlim:
|
||||
*/
|
||||
packet.ip6.ip6_hlim = IPPROTO_UDP;
|
||||
packet.udp.check = inet_cksum((uint16_t *)&packet + 2,
|
||||
offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size);
|
||||
/* fix 'hop limit' and 'next header' after UDP checksumming */
|
||||
packet.ip6.ip6_hlim = 8;
|
||||
packet.ip6.ip6_nxt = IPPROTO_UDP;
|
||||
|
||||
d6_dump_packet(d6_pkt);
|
||||
result = sendto(fd, &packet, offsetof(struct ip6_udp_d6_packet, data) + d6_pkt_size,
|
||||
/*flags:*/ 0,
|
||||
(struct sockaddr *) &dest_sll, sizeof(dest_sll)
|
||||
);
|
||||
msg = "sendto";
|
||||
ret_close:
|
||||
close(fd);
|
||||
if (result < 0) {
|
||||
ret_msg:
|
||||
bb_perror_msg(msg, "PACKET");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Let the kernel do all the work for packet generation */
|
||||
int FAST_FUNC d6_send_kernel_packet(
|
||||
struct d6_packet *d6_pkt, unsigned d6_pkt_size,
|
||||
struct in6_addr *src_ipv6, int source_port,
|
||||
struct in6_addr *dst_ipv6, int dest_port)
|
||||
{
|
||||
struct sockaddr_in6 sa;
|
||||
int fd;
|
||||
int result = -1;
|
||||
const char *msg;
|
||||
|
||||
fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (fd < 0) {
|
||||
msg = "socket(%s)";
|
||||
goto ret_msg;
|
||||
}
|
||||
setsockopt_reuseaddr(fd);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = htons(source_port);
|
||||
sa.sin6_addr = *src_ipv6; /* struct copy */
|
||||
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
msg = "bind(%s)";
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = htons(dest_port);
|
||||
sa.sin6_addr = *dst_ipv6; /* struct copy */
|
||||
if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
|
||||
msg = "connect";
|
||||
goto ret_close;
|
||||
}
|
||||
|
||||
d6_dump_packet(d6_pkt);
|
||||
result = safe_write(fd, d6_pkt, d6_pkt_size);
|
||||
msg = "write";
|
||||
ret_close:
|
||||
close(fd);
|
||||
if (result < 0) {
|
||||
ret_msg:
|
||||
bb_perror_msg(msg, "UDP");
|
||||
}
|
||||
return result;
|
||||
}
|
34
networking/udhcp/d6_socket.c
Normal file
34
networking/udhcp/d6_socket.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* vi: set sw=4 ts=4: */
|
||||
/*
|
||||
* Copyright (C) 2011 Denys Vlasenko.
|
||||
*
|
||||
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "d6_common.h"
|
||||
#include <net/if.h>
|
||||
|
||||
int FAST_FUNC d6_listen_socket(int port, const char *inf)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in6 addr;
|
||||
|
||||
log1("Opening listen socket on *:%d %s", port, inf);
|
||||
fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
setsockopt_reuseaddr(fd);
|
||||
if (setsockopt_broadcast(fd) == -1)
|
||||
bb_perror_msg_and_die("SO_BROADCAST");
|
||||
|
||||
/* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
|
||||
if (setsockopt_bindtodevice(fd, inf))
|
||||
xfunc_die(); /* warning is already printed */
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
/* addr.sin6_addr is all-zeros */
|
||||
xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
return fd;
|
||||
}
|
Loading…
Reference in New Issue
Block a user