diff options
| -rw-r--r-- | arp.c | 75 | ||||
| -rw-r--r-- | arp.h | 20 | ||||
| -rw-r--r-- | common.c | 7 | ||||
| -rw-r--r-- | defs.h | 2 | ||||
| -rw-r--r-- | dhcp-common.h | 2 | ||||
| -rw-r--r-- | dhcp.c | 859 | ||||
| -rw-r--r-- | dhcp.h | 25 | ||||
| -rw-r--r-- | dhcpcd.conf | 9 | ||||
| -rw-r--r-- | eloop.c | 1 | ||||
| -rw-r--r-- | if-bsd.c | 4 | ||||
| -rw-r--r-- | if-linux.c | 56 | ||||
| -rw-r--r-- | if-options.c | 51 | ||||
| -rw-r--r-- | if-options.h | 8 | ||||
| -rw-r--r-- | if-sun.c | 4 | ||||
| -rw-r--r-- | if.h | 4 | ||||
| -rw-r--r-- | ipv4.c | 2 | ||||
| -rw-r--r-- | ipv4ll.c | 10 |
17 files changed, 1030 insertions, 109 deletions
@@ -56,7 +56,7 @@ (sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN)) ssize_t -arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip) +arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip, const unsigned char *hwaddr) { uint8_t arp_buffer[ARP_LEN]; struct arphdr ar; @@ -85,13 +85,13 @@ arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip) #define ZERO(l) CHECK(memset, 0, l) APPEND(&ar, sizeof(ar)); - APPEND(ifp->hwaddr, ifp->hwlen); - APPEND(&sip, sizeof(sip)); - ZERO(ifp->hwlen); - APPEND(&tip, sizeof(tip)); + APPEND(ifp->hwaddr, ifp->hwlen); // Piers: Sender HW address (SHA) + APPEND(&sip, sizeof(sip)); // Sender Protocol (IP) address (SPA) + ZERO(ifp->hwlen); // Target HW addr (THA) [0: Ignored in Request] + APPEND(&tip, sizeof(tip)); // Target Protocol (IP) addr (TPA) state = ARP_CSTATE(ifp); - return if_sendraw(ifp, state->fd, ETHERTYPE_ARP, arp_buffer, len); + return if_sendraw(ifp, state->fd, ETHERTYPE_ARP, arp_buffer, len, hwaddr); eexit: errno = ENOBUFS; @@ -134,7 +134,7 @@ arp_packet(void *arg) state = ARP_STATE(ifp); flags = 0; - bytes = if_readraw(ifp, state->fd, buf, sizeof(buf), &flags); + bytes = if_readraw(ifp, state->fd, buf, sizeof(buf), &flags, NULL); if (bytes == -1) { logger(ifp->ctx, LOG_ERR, "%s: arp if_readrawpacket: %m", ifp->name); @@ -174,7 +174,7 @@ arp_packet(void *arg) break; } if (ifn) { -#if 0 +#if 1 logger(ifp->ctx, LOG_DEBUG, "%s: ignoring ARP from self", ifp->name); #endif @@ -188,9 +188,12 @@ arp_packet(void *arg) /* Run the conflicts */ TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, astaten) { + char hwaddr_buf[HWADDR_LEN * 3]; +// logger(ifp->ctx, LOG_DEBUG, "%s: arp_packet() Looping sip: %s SHA: %s ", ifp->name, inet_ntoa(arm.sip), hwaddr_ntoa(hw_s, ar.ar_hln, hwaddr_buf, sizeof(hwaddr_buf))); if (astate->conflicted_cb) astate->conflicted_cb(astate, &arm); } +// logger(ifp->ctx, LOG_DEBUG, "%s: arp_packet() Looped", ifp->name); } int @@ -241,7 +244,7 @@ arp_announce1(void *arg) "%s: ARP announcing %s (%d of %d)", ifp->name, inet_ntoa(astate->addr), astate->claims, ANNOUNCE_NUM); - if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr) == -1) + if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr, NULL) == -1) logger(ifp->ctx, LOG_ERR, "send_arp: %m"); eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT, astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced, @@ -266,7 +269,8 @@ arp_probed(void *arg) { struct arp_state *astate = arg; - astate->probed_cb(astate); + if (astate->probed_cb) + astate->probed_cb(astate); } static void @@ -287,13 +291,24 @@ arp_probe1(void *arg) tv.tv_nsec = 0; eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probed, astate); } - logger(ifp->ctx, LOG_DEBUG, - "%s: ARP probing %s (%d of %d), next in %0.1f seconds", - ifp->name, inet_ntoa(astate->addr), - astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM, - timespec_to_double(&tv)); - if (arp_request(ifp, 0, astate->addr.s_addr) == -1) - logger(ifp->ctx, LOG_ERR, "send_arp: %m"); + if (astate->tipaddr.s_addr) { + logger(ifp->ctx, LOG_DEBUG, + "%s: DNA probing %s (%d of %d), next in %0.1f seconds", + ifp->name, inet_ntoa(astate->addr), + astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM, + timespec_to_double(&tv)); + if (arp_request(ifp, astate->addr.s_addr, astate->tipaddr.s_addr, + astate->hwaddr) == -1) + logger(ifp->ctx, LOG_ERR, "send_dna: %m"); + } else { + logger(ifp->ctx, LOG_DEBUG, + "%s: ARP probing %s (%d of %d), next in %0.1f seconds", + ifp->name, inet_ntoa(astate->addr), + astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM, + timespec_to_double(&tv)); + if (arp_request(ifp, 0, astate->addr.s_addr, NULL) == -1) + logger(ifp->ctx, LOG_ERR, "send_arp: %m"); + } } void @@ -329,7 +344,7 @@ out: } struct arp_state * -arp_new(struct interface *ifp, const struct in_addr *addr) +arp_new(struct interface *ifp, const struct in_addr *addr, const unsigned char *hwaddr, const struct in_addr *tipaddr) { struct iarp_state *state; struct arp_state *astate; @@ -344,7 +359,7 @@ arp_new(struct interface *ifp, const struct in_addr *addr) state->fd = -1; TAILQ_INIT(&state->arp_states); } else { - if (addr && (astate = arp_find(ifp, addr))) + if (addr && (astate = arp_find(ifp, addr)) && !tipaddr) return astate; } @@ -355,6 +370,10 @@ arp_new(struct interface *ifp, const struct in_addr *addr) astate->iface = ifp; if (addr) astate->addr = *addr; + if (tipaddr) + astate->tipaddr = *tipaddr; + if (hwaddr) + memcpy(astate->hwaddr, hwaddr, ifp->hwlen); state = ARP_STATE(ifp); TAILQ_INSERT_TAIL(&state->arp_states, astate, next); return astate; @@ -395,6 +414,24 @@ arp_free(struct arp_state *astate) } } +void +arp_free_dna_but1(struct interface *ifp, struct bootp *bootp) +{ + struct iarp_state *state; + + if ((state = ARP_STATE(ifp)) != NULL) { + struct arp_state *p, *n; + + TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) { + if (p->dna_lease) + if (p->dna_lease->bootp != bootp && p->tipaddr.s_addr) { + free(p->dna_lease->bootp); + arp_free(p); + } + } + } +} + static void arp_free_but1(struct interface *ifp, struct arp_state *astate) { @@ -42,13 +42,14 @@ #include "dhcpcd.h" #include "if.h" +#include "dhcp.h" struct arp_msg { uint16_t op; - unsigned char sha[HWADDR_LEN]; - struct in_addr sip; - unsigned char tha[HWADDR_LEN]; - struct in_addr tip; + unsigned char sha[HWADDR_LEN]; // Sender HW addr/MAC (SHA) + struct in_addr sip; // Sender Protocol (IP) address (SPA) + unsigned char tha[HWADDR_LEN]; // Target HW addr (THA) [0: Ignored in Request] + struct in_addr tip; // Target Protocol (IP) addr (TPA) }; struct arp_state { @@ -61,6 +62,10 @@ struct arp_state { void (*free_cb)(struct arp_state *); struct in_addr addr; + struct in_addr tipaddr; + unsigned char hwaddr[HWADDR_LEN]; //Piers: DNA + struct dhcp_lease *dna_lease; + int probes; int claims; struct in_addr failed; @@ -78,15 +83,18 @@ struct iarp_state { ((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP]) #ifdef INET +struct bootp; int arp_open(struct interface *); -ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t); +ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t, const unsigned char *hwaddr); void arp_report_conflicted(const struct arp_state *, const struct arp_msg *); void arp_announce(struct arp_state *); void arp_probe(struct arp_state *); -struct arp_state *arp_new(struct interface *, const struct in_addr *); +void dna_probe(struct arp_state *); +struct arp_state *arp_new(struct interface *, const struct in_addr *, const unsigned char *, const struct in_addr *); void arp_cancel(struct arp_state *); void arp_free(struct arp_state *); void arp_free_but(struct arp_state *); +void arp_free_dna_but1(struct interface *, struct bootp *); struct arp_state *arp_find(struct interface *, const struct in_addr *); void arp_close(struct interface *); @@ -185,6 +185,13 @@ logger(struct dhcpcd_ctx *ctx, int pri, const char *fmt, ...) if (ctx && ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST)) goto out; + if (pri < LOG_DEBUG || (ctx->options & DHCPCD_DEBUG)) { + struct timeval tv; + if (gettimeofday(&tv, NULL) != -1) { + fprintf(stdout, "%ld.%ld:", tv.tv_sec,tv.tv_usec); + } + } + if (ctx && ctx->log_fd != -1) { if (pri < LOG_DEBUG || (ctx->options & DHCPCD_DEBUG)) { struct timeval tv; @@ -28,7 +28,7 @@ #define CONFIG_H #define PACKAGE "dhcpcd" -#define VERSION "6.11.1" +#define VERSION "6.11.1-DIP-v2.1" #ifndef CONFIG # define CONFIG SYSCONFDIR "/" PACKAGE ".conf" diff --git a/dhcp-common.h b/dhcp-common.h index 61eccf18..e7d98c1b 100644 --- a/dhcp-common.h +++ b/dhcp-common.h @@ -118,6 +118,6 @@ size_t dhcp_envoption(struct dhcpcd_ctx *, const uint8_t *, size_t, struct dhcp_opt **), const uint8_t *od, size_t ol); void dhcp_zero_index(struct dhcp_opt *); -size_t dhcp_read_lease_fd(int, uint8_t **); +size_t dhcp_read_lease_fd(int fd, uint8_t **lease); #endif @@ -50,6 +50,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <glob.h> //Piers: dna_file #define ELOOP_QUEUE 2 #include "config.h" @@ -119,6 +120,9 @@ struct udp_bootp_packet static int dhcp_open(struct interface *); static void dhcp_arp_conflicted(struct arp_state *, const struct arp_msg *); +void dhcp_dna_addresses(struct interface *); + +static void dhcp_reboot(struct interface *); void dhcp_printoptions(const struct dhcpcd_ctx *ctx, @@ -1109,18 +1113,544 @@ write_lease(const struct interface *ifp, const struct bootp *bootp, size_t len) int fd; ssize_t bytes; const struct dhcp_state *state = D_CSTATE(ifp); + char *dna_fname, *hwaddr_str; + const char *file_ext=".lease"; + const struct dhcp_lease *lease = &state->lease; + struct if_options *ifo = ifp->options; logger(ifp->ctx, LOG_DEBUG, "%s: writing lease `%s'", ifp->name, state->leasefile); + // Piers: Only writes one lease as O_TRUNC sets file len to zero fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) return -1; bytes = write(fd, bootp, len); close(fd); + + if (ifo->options & DHCPCD_DNA) { + dna_fname=malloc(strlen(state->leasefile)+2*(size_t)ifp->hwlen+2); + strncpy(dna_fname, state->leasefile, + strlen(state->leasefile)-strlen(file_ext)); + hwaddr_str=&dna_fname[strlen(state->leasefile)-strlen(file_ext)+1]; + hwaddr_str[-1]='-'; + for (int i=0; i<ifp->hwlen; i++) + sprintf(&hwaddr_str[i*2],"%02x",lease->hwaddr[i]); + hwaddr_str[ifp->hwlen*2]='\0'; + strcat(dna_fname,file_ext); + + logger(ifp->ctx, LOG_DEBUG, "%s: writing DNA lease:'%s'", + ifp->name, dna_fname); + fd = open(dna_fname, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) + return -1; + bytes = write(fd, bootp, len); + close(fd); + free(dna_fname); + } return bytes; } +/*int globerr(const char *epath, int eerrno) +{ + printf("epath: %s, eerrno: %d\n", epath , eerrno); + return 0; +}*/ +static void +get_lease(struct interface *, struct dhcp_lease *, const struct bootp *, size_t); + +int +dhcp_dna_dummy_addr(struct interface *ifp, struct dhcp_lease **dna_leases) +{ + struct dhcp_state *state = D_STATE(ifp); + struct dhcp_lease *lease; + uint32_t rand; + + if (ifp->options->dna_dum == -1) { + /* Auto mode */ + ifp->options->dna_dum = state->dna_lease_len/2; + } + for (int i=0; i< ifp->options->dna_dum; i++) { + char buf[HWADDR_LEN * 3]; + + if ((*dna_leases = realloc(*dna_leases, sizeof(struct dhcp_lease)* + (state->dna_lease_len + 1))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: realloc: %m", __func__); + return 0; + } + lease = &(*dna_leases)[state->dna_lease_len]; + + *lease = lease[-1]; + lease->bootp = malloc(lease[-1].bootp_len); + memcpy(lease->bootp, lease[-1].bootp, lease[-1].bootp_len); + rand = arc4random(); + lease->hwaddr[3]=(unsigned char)rand; + rand>>=8; + lease->hwaddr[4]=(unsigned char)rand; + rand>>=8; + lease->hwaddr[5]=(unsigned char)rand; + + state->dna_lease_len++; + + logger(ifp->ctx, LOG_DEBUG, "%s: Dummy MAC is hwaddr %s", + ifp->name, hwaddr_ntoa(lease->hwaddr, ifp->hwlen, + buf, sizeof(buf))); + } +} + +static size_t +read_dna_leases(struct interface *ifp, struct dhcp_lease **dna_leases) +{ + size_t i; + int j, fd; + size_t bytes; + uint8_t *bootp; + struct dhcp_state *state = D_STATE(ifp); + glob_t globbuf; + char *globstr, *chaddr_str_start; + char *mac_glob; + const char *mac_byte_glob="[A-Fa-f0-9][A-Fa-f0-9]"; + const char *file_ext=".lease"; + struct stat st; + struct dhcp_lease lease; + + state->dna_lease_len=0; + mac_glob=malloc(ifp->hwlen*sizeof(char)*strlen(mac_byte_glob)+2); + if (mac_glob == NULL) { + // Note %m results in printing of errno + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return 0; + } + mac_glob[0]='-'; + mac_glob[1]='\0'; + for (i=0; i < ifp->hwlen; i++) + strcat(mac_glob,mac_byte_glob); + + globstr=malloc(strlen(state->leasefile)+strlen(mac_glob)+1); + if (globstr == NULL) { + // Note %m results in printing of errno + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return 0; + } + strncpy(globstr, state->leasefile, strlen(state->leasefile)-strlen(file_ext)); + globstr[strlen(state->leasefile)-strlen(file_ext)]='\0'; + strcat(globstr, mac_glob); + strcat(globstr, file_ext); + if ((j=glob(globstr, 0, NULL, &globbuf))) { + if (j==GLOB_NOMATCH) + logger(ifp->ctx, LOG_DEBUG, "%s: No DNA leases found", + ifp->name); + else + logger(ifp->ctx, LOG_DEBUG, "%s: No DNA leases found (Err:%d)", + ifp->name, j); + free(mac_glob); + return 0; + } + logger(ifp->ctx, LOG_DEBUG, "%s: Number of DNA lease files found: %lu", + ifp->name,globbuf.gl_pathc); + for (i=0; i < globbuf.gl_pathc; i++) { + logger(ifp->ctx, LOG_DEBUG, "%s: DNA lease[%ld]: %s", + ifp->name, i, globbuf.gl_pathv[i]); + fd = open(globbuf.gl_pathv[i], O_RDONLY); + if (fd == -1) { + logger(ifp->ctx, LOG_DEBUG, "%s: Skipping Bad DNA lease[%lu]: %s", + ifp->name, i, globbuf.gl_pathv[i]); + continue; + } + bytes = dhcp_read_lease_fd(fd, &bootp); + close(fd); + if (bytes == 0) { + free(bootp); + logger(ifp->ctx, LOG_ERR, "%s: dhcp_read_lease_fd", __func__); + continue; + } + + /* Ensure the packet is at least BOOTP sized + * with a vendor area of 4 octets + * (it should be more, and our read packet enforces this so this + * code should not be needed, but of course people could + * scribble whatever in the stored lease file. */ + if (bytes < offsetof(struct bootp, vend) + 4) { + free(bootp); + logger(ifp->ctx, LOG_ERR, "%s: truncated bootp", __func__); + continue; + } + + get_lease(ifp, &lease, (const struct bootp *)bootp, bytes); + + if (lease.leasetime != ~0U && + stat(globbuf.gl_pathv[i], &st) == 0) + { + time_t now; + uint32_t l; + + /* Offset lease times and check expiry */ + now = time(NULL); + if (now == -1 || + (time_t)lease.leasetime < now - st.st_mtime) + { + logger(ifp->ctx, LOG_DEBUG, + "%s: deleting expired DNA lease", ifp->name); + unlink(globbuf.gl_pathv[i]); + free(bootp); + continue; + } else { + l = (uint32_t)(now - st.st_mtime); + lease.leasetime -= l; + lease.renewaltime -= l; + lease.rebindtime -= l; + } + } + + if (*dna_leases == NULL) { + if ((*dna_leases = malloc(sizeof(struct dhcp_lease))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return 0; + } + } else { + if ((*dna_leases = realloc(*dna_leases, sizeof(struct + dhcp_lease)*(state->dna_lease_len+1))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: realloc: %m", __func__); + return 0; + } + } + (*dna_leases)[state->dna_lease_len]=lease; + chaddr_str_start=globbuf.gl_pathv[i]+strlen(globbuf.gl_pathv[i])-ifp->hwlen*2-strlen(file_ext); + (*dna_leases)[state->dna_lease_len].bootp_len = bytes; + char c[3]; + c[2]='\0'; + for (j=0; j<ifp->hwlen*2; j+=2) { + c[0]=chaddr_str_start[j]; + c[1]=chaddr_str_start[j+1]; + (*dna_leases)[state->dna_lease_len].hwaddr[j/2] = + (uint8_t)strtol(c, NULL, 16); + //logger(ifp->ctx, LOG_DEBUG, "%s: Converted DNA lease[%d]: %s: %d", ifp->name,i, c, (uint8_t)strtol(c, NULL, 16)); + } + (*dna_leases)[state->dna_lease_len++].bootp = (struct bootp *)bootp; + } + logger(ifp->ctx, LOG_DEBUG, "%s: DNA valid leases: %lu", ifp->name, + state->dna_lease_len); + if (state->dna_lease_len && ifp->options->dna_dum) + dhcp_dna_dummy_addr(ifp, dna_leases); + free(mac_glob); + globfree(&globbuf); + free(globstr); + logger(ifp->ctx, LOG_DEBUG, "%s: DNA active leases: %lu", ifp->name, + state->dna_lease_len); + return state->dna_lease_len; +} + +/* in[] ---> Input Array + istart & iend ---> Staring and Ending indexes in in[] + combotmp[] ---> Temporary array to store current combination + cindex ---> Current index in combo[] + r ---> Requested Number of elements per combination + out Output array of combinations + out_num Number elements in output array */ +void combinationUtil(int in[], int combotmp[], int istart, int iend, + int cindex, int r, int **out, int *out_num) +{ + // Current combination is ready to be stored + if (cindex == r) + { + if (*out==NULL) + *out=malloc(sizeof(int)*r); + else + *out=realloc(*out, (*out_num+1)*sizeof(int)*r); + if (out == NULL) { + // Note %m results in printing of errno + //logger(ifp->ctx, LOG_ERR, "%s: {m/re}alloc: %m", __func__); + return; + } + for (int j=0; j<r; j++) { + (*out)[*out_num*r+j]=combotmp[j]; + printf("%d ", combotmp[j]); + } + printf("\n"); + (*out_num)++; + return; + } + + // replace cindex with all possible elements. The condition + // "iend-i+1 >= r-cindex" makes sure that including one element + // at cindex will make a combination with remaining elements + // at remaining positions + for (int i=istart; i<=iend && iend-i+1 >= r-cindex; i++) + { + combotmp[cindex] = in[i]; + combinationUtil(in, combotmp, i+1, iend, cindex+1, r, out, out_num); + } +} + +#include <curl/curl.h> +#include <string.h> + +struct MemoryStruct { + char *memory; + size_t size; +}; + +static size_t +WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)userp; + + mem->memory = realloc(mem->memory, mem->size + realsize + 1); + if(mem->memory == NULL) { + /* out of memory! */ + printf("not enough memory (realloc returned NULL)\n"); + return 0; + } + + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +int query_geo_macs(struct interface *ifp, int combonum, int *combomap, char **dna_macs, int *geolocated) { + CURL *curlhandle; + CURLcode res; + struct MemoryStruct chunk; + char* jsonObj = "{\"considerIp\": \"false\",\"wifiAccessPoints\": [\ + { \"macAddress\": \"%s\"},{ \"macAddress\": \"%s\"}]}"; + char dynObj[strlen(jsonObj)+2*(5*2+5)]; + struct curl_slist *headers = NULL; + int i, numlocated=0; + + chunk.memory = malloc(1); /* will be grown as needed by the realloc above */ + if (chunk.memory == NULL) { + //logger(ifp->ctx, LOG_ERR, "%s: realloc: %m", __func__); + printf("%s: realloc: %m", __func__); + return -1; + } + + curl_global_init(CURL_GLOBAL_ALL); + curlhandle = curl_easy_init(); + if (curlhandle == NULL) { + return -1; + } + /* send all data to this function */ + curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* we pass our 'chunk' struct to the callback function */ + curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, (void *)&chunk); + + headers = curl_slist_append(headers, "Accept: application/json"); + headers = curl_slist_append(headers, "Content-Type: application/json"); + headers = curl_slist_append(headers, "charsets: utf-8"); + + curl_easy_setopt(curlhandle, CURLOPT_URL, ifp->options->dna_gurl); + + curl_easy_setopt(curlhandle, CURLOPT_CUSTOMREQUEST, "POST"); + curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curlhandle, CURLOPT_POSTFIELDS, dynObj); + curl_easy_setopt(curlhandle, CURLOPT_USERAGENT, "libcurl/1.1"); + + printf("GEO Checking %d leases with geolocation provider: %s\n",combonum, ifp->options->dna_gurl); + for (i=0; i<combonum; i++) { + + sprintf(dynObj, jsonObj, dna_macs[combomap[i*2]], dna_macs[combomap[i*2+1]]); + + printf("MAC Check #%d:%s\n",i, dynObj); + + chunk.size = 0; /* set the data chunk size to zero */ + res = curl_easy_perform(curlhandle); + + /* check for errors */ + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } else { + printf("Curl recieved %lu bytes:\n", (long)chunk.size); + printf("%s\n", chunk.memory); + if (!strcasestr(chunk.memory,"error")) { + geolocated[numlocated++]=i; + } + } + } + free(chunk.memory); + curl_easy_cleanup(curlhandle); + curl_global_cleanup(); + return numlocated; +} + +void check_dna_geo(struct interface *ifp) +{ + //size_t i; + int i, j, fd; + size_t bytes; + uint8_t *bootp; + struct dhcp_state *state = D_STATE(ifp); + glob_t globbuf; + char *globstr, *chaddr_str_start; + char *mac_glob; + const char *mac_byte_glob="[A-Fa-f0-9][A-Fa-f0-9]"; + const char *file_ext=".lease"; + struct stat st; + int dna_mac_len, k; + char **dna_macs; + + mac_glob=malloc(ifp->hwlen*sizeof(char)*strlen(mac_byte_glob)+2); + if (mac_glob == NULL) { + // Note %m results in printing of errno + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return; + } + mac_glob[0]='-'; + mac_glob[1]='\0'; + for (i=0; i < ifp->hwlen; i++) + strcat(mac_glob,mac_byte_glob); + + globstr=malloc(strlen(state->leasefile)+strlen(mac_glob)+1); + if (globstr == NULL) { + // Note %m results in printing of errno + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return; + } + strncpy(globstr, state->leasefile, strlen(state->leasefile)-strlen(file_ext)); + globstr[strlen(state->leasefile)-strlen(file_ext)]='\0'; + strcat(globstr, mac_glob); + strcat(globstr, file_ext); + //printf("DNA Globstr:'%s (strlen:%lu, sizeof:%lu')\n",globstr, strlen(globstr), sizeof(globstr)); + if ((j=glob(globstr, GLOB_NOSORT, NULL, &globbuf))) { + if (j==GLOB_NOMATCH) + logger(ifp->ctx, LOG_DEBUG, "%s: No DNA leases found", + ifp->name); + else + logger(ifp->ctx, LOG_DEBUG, "%s: No DNA leases found (Err:%d)", + ifp->name, j); + free(mac_glob); + return; + } + logger(ifp->ctx, LOG_DEBUG, "%s: DNA leases: %lu", + ifp->name, globbuf.gl_pathc); + + unsigned long remaining = globbuf.gl_pathc; + + dna_mac_len = ifp->hwlen*2+6; + if ((dna_macs = malloc(globbuf.gl_pathc*sizeof(char*))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return; + } + if ((dna_macs[0] = malloc(globbuf.gl_pathc*dna_mac_len*sizeof(char))) == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__); + return; + } + // Explicitly set pointer values http://www.c-faq.com/aryptr/dynmuldimary.html + for (i=1; i< globbuf.gl_pathc; i++) + dna_macs[i]=dna_macs[0]+i*dna_mac_len; + + // Extract DNA MACs + for (i=0; i < globbuf.gl_pathc; i++) { + logger(ifp->ctx, LOG_DEBUG, "%s: DNA lease[%d]: %s", + ifp->name, i, globbuf.gl_pathv[i]); + + chaddr_str_start=globbuf.gl_pathv[i]+strlen(globbuf.gl_pathv[i])-ifp->hwlen*2-strlen(file_ext); + k=0; + for (j=0; j<ifp->hwlen*2; j+=2) { + memcpy(dna_macs[i]+k,&chaddr_str_start[j],2); + dna_macs[i][k+2]=':'; + k+=3; + } + dna_macs[i][k-1]='\0'; + logger(ifp->ctx, LOG_DEBUG, "%s: Extracted DNA lease[%d]: %s", ifp->name,i, dna_macs[i]); + } + + if (globbuf.gl_pathc > 1) { + int tmp[2], c, matches=0; + int combonum=0; + int *combomap=NULL; + int *in=NULL; + int numlocated; + + in = malloc(sizeof(int)*globbuf.gl_pathc); + // Set in array to containing an index of the existing MACs + for (i=0; i < globbuf.gl_pathc; i++) + in[i]=i; + + printf("Generating Combos*******************\n"); + + // Recursively generate all combinations + combinationUtil(in, tmp, 0, globbuf.gl_pathc-1, 0, 2, &combomap, &combonum); + int dna_mac_rm[combonum]; + int *geolocated = malloc(combonum*sizeof(int)); /* will be grown as needed by the realloc above */ + if (geolocated == NULL) { + //logger(ifp->ctx, LOG_ERR, "%s: realloc: %m", __func__); + printf("%s: realloc: %m", __func__); + return; + } + printf("Querying Combos*******************\n"); + numlocated = query_geo_macs(ifp, combonum, combomap, dna_macs, geolocated); + printf("Matched Combos:%d\n", numlocated); + + // reset in array for count mutually matching MACs + for (i=0; i < globbuf.gl_pathc; i++) + in[i]=0; + // Find any mutual matching MACs + for (i=0; i < numlocated; i++) { + for (j=i+1; j < numlocated; j++) { + if ((c=combomap[geolocated[i]*2]) == + combomap[geolocated[j]*2]) + in[c]++; + if (c==combomap[geolocated[j]*2+1]) + in[c]++; + if ((c=combomap[geolocated[i]*2+1]) == + combomap[geolocated[j]*2]) + in[c]++; + if (c==combomap[geolocated[j]*2+1]) + in[c]++; + } + } + for (i=0; i < globbuf.gl_pathc; i++) { + printf("Checking Mutual Matching MACs[%d]:%d\n", i, in[i]); + if (in[i]) { + matches++; + logger(ifp->ctx, LOG_DEBUG, + "%s: deleting GEOmatched Mutual DNA lease:[%d] %s", ifp->name, i, globbuf.gl_pathv[i]); + unlink(globbuf.gl_pathv[i]); + remaining--; + } + } + printf("Total seperate Mutual Matching MACs:%d\n", matches); + int already_mutual_matched=0; + for (i=0; i < globbuf.gl_pathc; i++) { + for (j=0; j< numlocated; j++) { + if (in[i]) { + if (i == combomap[geolocated[j]*2]) + already_mutual_matched++; + if (i == combomap[geolocated[j]*2+1]) + already_mutual_matched++; + } + } + } + if (already_mutual_matched != numlocated) { + for (i=0; i< numlocated; i++) { + // Random choice as to which lease is deleted: one needs to go.. + if (arc4random() > 0x3FFFFFFF) { + c=combomap[geolocated[i]*2]; + unlink(globbuf.gl_pathv[c]); + remaining--; + logger(ifp->ctx, LOG_DEBUG, + "%s: deleting GEOmatched DNA lease:[%d] %s", ifp->name, c,globbuf.gl_pathv[c]); + } else { + c=combomap[geolocated[i]*2+1]; + unlink(globbuf.gl_pathv[c]); + remaining--; + logger(ifp->ctx, LOG_DEBUG, + "%s: deleting GEOmatched DNA lease:[%d] %s", ifp->name, c,globbuf.gl_pathv[c]); + } + } + } + } + free(mac_glob); + globfree(&globbuf); + free(globstr); + logger(ifp->ctx, LOG_DEBUG, "%s: Remaining DNA active leases - after GEOmatch test: %lu", ifp->name, remaining); +} + + static size_t read_lease(struct interface *ifp, struct bootp **bootp) { @@ -1753,7 +2283,7 @@ send_message(struct interface *ifp, uint8_t type, logger(ifp->ctx, LOG_ERR, "dhcp_makeudppacket: %m"); } else { r = if_sendraw(ifp, state->raw_fd, - ETHERTYPE_IP, (uint8_t *)udp, ulen); + ETHERTYPE_IP, (uint8_t *)udp, ulen, NULL); free(udp); } /* If we failed to send a raw packet this normally means @@ -1870,7 +2400,7 @@ dhcp_leaseextend(struct interface *ifp) if (ifp->options->options & DHCPCD_ARP) { struct arp_state *astate; - if ((astate = arp_new(ifp, NULL)) == NULL) + if ((astate = arp_new(ifp, NULL, NULL, NULL)) == NULL) return -1; if (arp_open(ifp) == -1) @@ -1979,19 +2509,25 @@ dhcp_arp_probed(struct arp_state *astate) { struct dhcp_state *state; struct if_options *ifo; + struct interface *ifp; + + ifp = astate->iface; state = D_STATE(astate->iface); ifo = astate->iface->options; - if (state->arping_index < ifo->arping_len) { + if (state->arping_index != -1 && + state->arping_index < ifo->arping_len) { /* We didn't find a profile for this * address or hwaddr, so move to the next * arping profile */ if (++state->arping_index < ifo->arping_len) { astate->addr.s_addr = - ifo->arping[state->arping_index - 1]; + ifo->arping[state->arping_index]; arp_probe(astate); + return; } - dhcpcd_startinterface(astate->iface); + arp_free(astate); + dhcpcd_startinterface(ifp); return; } @@ -2032,6 +2568,84 @@ dhcp_arp_probed(struct arp_state *astate) } static void +dhcp_dna_probed(struct arp_state *astate) +{ + logger(astate->iface->ctx, LOG_DEBUG, "%s: DNA timed out for %s", + astate->iface->name, inet_ntoa(astate->addr)); + arp_free(astate); +} + + +static void +dhcp_dna_response(struct arp_state *astate, const struct arp_msg *amsg) +{ + struct interface *ifp; + struct dhcp_state *state; + char *sip_str=strdup(inet_ntoa(amsg->sip)); + + ifp = astate->iface; + state = D_STATE(ifp); + + if (!memcmp(amsg->sha, astate->hwaddr, ifp->hwlen)) { + logger(astate->iface->ctx, LOG_DEBUG, + "%s: DNA MATCHING response received for astate:%s, Sender IP:%s", + astate->iface->name, inet_ntoa(astate->addr), sip_str); + if (state->state == DHS_INIT || state->state == DHS_DISCOVER) { + struct ipv4_addr *ia; + state->offer= astate->dna_lease->bootp; + state->offer_len = astate->dna_lease->bootp_len; + state->dna_matched_lease = astate->dna_lease->bootp; + state->lease = *astate->dna_lease; + state->lease.frominfo = 1; + if (state->new == NULL && + (ia = ipv4_iffindaddr(ifp, + &state->lease.addr, &state->lease.mask)) != NULL) + { + /* We still have the IP address from the + * last lease. Fake add the address and + * routes from it so the lease + * can be cleaned up. */ + state->new = malloc(state->offer_len); + if (state->new) { + memcpy(state->new, + state->offer, state->offer_len); + state->new_len = state->offer_len; + state->addr = ia; + state->added |= STATE_ADDED | STATE_FAKE; + ipv4_buildroutes(ifp->ctx); + } else + logger(ifp->ctx, LOG_ERR, "%s: %m", + __func__); + } + logger(astate->iface->ctx, LOG_DEBUG, + "%s: DNA initiated reboot Sender IP:%s", + astate->iface->name, sip_str); + dhcp_reboot(ifp); + } else { + logger(astate->iface->ctx, LOG_DEBUG, + "%s: DNA reboot NOT initiated as state is:%d", + astate->iface->name, state->state); + } + arp_free(astate); + free(sip_str); + return; + } else { + logger(astate->iface->ctx, LOG_DEBUG, + "%s: DNA Non-Matching response received for astate:%s, Sender IP:%s", + astate->iface->name, inet_ntoa(astate->addr), sip_str); + if (state->state == DHS_BOUND) { + logger(astate->iface->ctx, LOG_DEBUG, + "%s: DHCP Bound so DNA terminated for astate:%s, Sender IP:%s", + astate->iface->name, inet_ntoa(astate->addr), sip_str); + arp_free_dna_but1(astate->iface, NULL); + free(state->dna_leases); + state->dna_leases=NULL; + } + } + free(sip_str); +} + +static void dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) { struct interface *ifp; @@ -2041,17 +2655,18 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) ifp = astate->iface; ifo = ifp->options; state = D_STATE(ifp); - if (state->arping_index && - state->arping_index <= ifo->arping_len && + /* Piers: This if is only entered if any ARPING entries are configured */ + if (state->arping_index != -1 && + state->arping_index < ifo->arping_len && amsg && - (amsg->sip.s_addr == ifo->arping[state->arping_index - 1] || + (amsg->sip.s_addr == ifo->arping[state->arping_index] || (amsg->sip.s_addr == 0 && - amsg->tip.s_addr == ifo->arping[state->arping_index - 1]))) + amsg->tip.s_addr == ifo->arping[state->arping_index]))) { char buf[HWADDR_LEN * 3]; - astate->failed.s_addr = ifo->arping[state->arping_index - 1]; - arp_report_conflicted(astate, amsg); + astate->failed.s_addr = ifo->arping[state->arping_index]; + arp_report_conflicted(astate, amsg); //Just log it hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf)); if (dhcpcd_selectprofile(ifp, buf) == -1 && dhcpcd_selectprofile(ifp, @@ -2231,13 +2846,15 @@ dhcp_bind(struct interface *ifp) ifp->name, lease->renewaltime, lease->rebindtime); } state->state = DHS_BOUND; - if (!state->lease.frominfo && - !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) + if ( !state->lease.frominfo && + !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) if (write_lease(ifp, state->new, state->new_len) == -1) logger(ifp->ctx, LOG_ERR, "%s: write_lease: %m", __func__); ipv4_applyaddr(ifp); + if (ifp->options->dna_pran) + check_dna_geo(ifp); } static void @@ -2292,6 +2909,72 @@ dhcp_message_new(struct bootp **bootp, return sizeof(**bootp); } +#define O_RANDOM 1 + +void dhcp_dna_order(size_t *map, size_t maplen, int order); + +void +dhcp_dna_order(size_t *map, size_t maplen, int order) +{ + size_t i, r, t; + + for (i=0; i < maplen; i++) + map[i]=i; + + if (order == O_RANDOM) { + /* Randomise order using Fisher–Yates Durstenfeld shuffle */ + for (i=maplen-1; i>0; i--) { + r = (size_t)arc4random_uniform(i); + t = map[i]; + map[i]= map[r]; + map[r]= t; + } + // printf("DNA Random map[%lu]:",maplen); + } else { + // printf("DNA NON-Random map[%lu]:",maplen); + } +/* for (i=0; i < maplen; i++) + printf("%lu, ",map[i]); + printf("\n");*/ +} + +void +dhcp_dna_addresses(struct interface *ifp) +{ + size_t i, *map; + struct dhcp_lease dlease; + struct in_addr saddr, yaddr; + struct arp_state *astate; + struct dhcp_state *state = D_STATE(ifp); + + if (!state->dna_lease_len) return; + + //eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + + map=malloc(state->dna_lease_len*sizeof(size_t)); + if (map == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); + return; + } + dhcp_dna_order(map, state->dna_lease_len, ifp->options->dna_ord); + + for (i=0; i < state->dna_lease_len; i++) { + dlease = state->dna_leases[map[i]]; + saddr.s_addr = dlease.bootp->siaddr; + yaddr.s_addr = dlease.bootp->yiaddr; + astate = arp_new(ifp, &yaddr, dlease.hwaddr, &saddr); + if (astate) { + // probed_cb is called after no response + astate->probed_cb = dhcp_dna_probed; + // 'conflicted_cb' called when response is received + astate->conflicted_cb = dhcp_dna_response; + astate->dna_lease = &state->dna_leases[map[i]]; + arp_probe(astate); + } + } + free(map); +} + static int dhcp_arp_address(struct interface *ifp) { @@ -2308,11 +2991,38 @@ dhcp_arp_address(struct interface *ifp) state->offer->ciaddr : state->offer->yiaddr; /* If the interface already has the address configured * then we can't ARP for duplicate detection. */ - ia = ipv4_findaddr(ifp->ctx, &addr); + ia = ipv4_findaddr(ifp->ctx, &addr); + + if (ifp->options->options & DHCPCD_DNA) { + if (state->dna_lease_len) { + arp_close(ifp); + if (state->dna_matched_lease != NULL) { + if (state->dna_matched_lease->yiaddr == + state->offer->yiaddr ) { + state->dna_matched_lease = NULL; + logger(ifp->ctx, LOG_INFO, + "%s: Skip DAD as DNA address Match:%s", + ifp->name, inet_ntoa(addr)); + state->dna_lease_len=0; + arp_free_dna_but1(ifp, state->dna_matched_lease); + free(state->dna_leases); + state->dna_leases=NULL; + return 1; + } + } else { + logger(ifp->ctx, LOG_INFO, + "%s: DNA cancelled as no address match", ifp->name); + } + arp_free_dna_but1(ifp, NULL); + free(state->dna_leases); + state->dna_leases=NULL; + state->dna_lease_len=0; + } + } #ifdef IN_IFF_TENTATIVE if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { - if ((astate = arp_new(ifp, &addr)) != NULL) { + if ((astate = arp_new(ifp, &addr, NULL, NULL)) != NULL) { astate->probed_cb = dhcp_arp_probed; astate->conflicted_cb = dhcp_arp_conflicted; } @@ -2334,7 +3044,7 @@ dhcp_arp_address(struct interface *ifp) get_lease(ifp, &l, state->offer, state->offer_len); logger(ifp->ctx, LOG_INFO, "%s: probing address %s/%d", ifp->name, inet_ntoa(l.addr), inet_ntocidr(l.mask)); - if ((astate = arp_new(ifp, &addr)) != NULL) { + if ((astate = arp_new(ifp, &addr, NULL, NULL)) != NULL) { astate->probed_cb = dhcp_arp_probed; astate->conflicted_cb = dhcp_arp_conflicted; /* We need to handle DAD. */ @@ -2499,7 +3209,8 @@ dhcp_reboot(struct interface *ifp) logger(ifp->ctx, LOG_INFO, "%s: rebinding lease of %s", ifp->name, inet_ntoa(state->lease.addr)); - state->xid = dhcp_xid(ifp); + if (!state->xid) + state->xid = dhcp_xid(ifp); state->lease.server.s_addr = 0; eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); @@ -2536,6 +3247,9 @@ dhcp_drop(struct interface *ifp, const char *reason) return; } +#ifdef ARPING + state->arping_index = -1; +#endif if (ifp->options->options & DHCPCD_RELEASE && !(ifp->options->options & DHCPCD_INFORM)) { @@ -2679,7 +3393,7 @@ log_dhcp(int lvl, const char *msg, static void dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, - const struct in_addr *from) + const struct in_addr *from, const unsigned char *hwaddr) { struct dhcp_state *state = D_STATE(ifp); struct if_options *ifo = ifp->options; @@ -2725,7 +3439,7 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, type = 0; else if (ifo->options & DHCPCD_BOOTP) { logger(ifp->ctx, LOG_DEBUG, - "%s: ignoring DHCP reply (excpecting BOOTP)", + "%s: ignoring DHCP reply (expecting BOOTP)", ifp->name); return; } @@ -2757,6 +3471,8 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, } LOGDHCP0(LOG_WARNING, "no authentication"); } + // Piers; Copy DHCP server hwaddr into lease + memcpy(lease->hwaddr, hwaddr, ifp->hwlen); /* RFC 3203 */ if (type == DHCP_FORCERENEW) { @@ -3133,11 +3849,12 @@ dhcp_handlepacket(void *arg) struct in_addr from; int i, flags; const struct dhcp_state *state = D_CSTATE(ifp); + unsigned char hwaddr[ETH_ALEN]; /* Need this API due to BPF */ flags = 0; bootp = NULL; - bytes = (size_t)if_readraw(ifp, state->raw_fd,buf, sizeof(buf), &flags); + bytes = (size_t)if_readraw(ifp, state->raw_fd, buf, sizeof(buf), &flags, hwaddr); if ((ssize_t)bytes == -1) { logger(ifp->ctx, LOG_ERR, "%s: dhcp if_readrawpacket: %m", ifp->name); @@ -3189,7 +3906,7 @@ dhcp_handlepacket(void *arg) while (bytes < offsetof(struct bootp, vend) + 4) bootp[bytes++] = '\0'; - dhcp_handledhcp(ifp, (struct bootp *)bootp, bytes, &from); + dhcp_handledhcp(ifp, (struct bootp *)bootp, bytes, &from, hwaddr); } static void @@ -3315,6 +4032,9 @@ dhcp_init(struct interface *ifp) return -1; /* 0 is a valid fd, so init to -1 */ state->raw_fd = -1; +#ifdef ARPING + state->arping_index = -1; +#endif /* Now is a good time to find IPv4 routes */ if_initrt(ifp->ctx); @@ -3392,45 +4112,11 @@ dhcp_start1(void *arg) uint32_t l; int nolease; - if (!(ifo->options & DHCPCD_IPV4)) - return; - - /* Listen on *.*.*.*:bootpc so that the kernel never sends an - * ICMP port unreachable message back to the DHCP server */ - if (ifp->ctx->udp_fd == -1) { - ifp->ctx->udp_fd = dhcp_openudp(NULL); - if (ifp->ctx->udp_fd == -1) { - /* Don't log an error if some other process - * is handling this. */ - if (errno != EADDRINUSE) - logger(ifp->ctx, LOG_ERR, - "%s: dhcp_openudp: %m", __func__); - } else - eloop_event_add(ifp->ctx->eloop, - ifp->ctx->udp_fd, dhcp_handleudp, ifp->ctx); - } - - if (dhcp_init(ifp) == -1) { - logger(ifp->ctx, LOG_ERR, "%s: dhcp_init: %m", ifp->name); - return; - } - state = D_STATE(ifp); clock_gettime(CLOCK_MONOTONIC, &state->started); free(state->offer); state->offer = NULL; - if (state->arping_index < ifo->arping_len) { - struct arp_state *astate; - - astate = arp_new(ifp, NULL); - if (astate) { - astate->probed_cb = dhcp_arp_probed; - astate->conflicted_cb = dhcp_arp_conflicted; - dhcp_arp_probed(astate); - } - return; - } if (ifo->options & DHCPCD_STATIC) { dhcp_static(ifp); @@ -3478,9 +4164,11 @@ dhcp_start1(void *arg) } } } + if (state->offer) { struct ipv4_addr *ia; + //Piers: Copy lease from file (state->offer) to state->lease get_lease(ifp, &state->lease, state->offer, state->offer_len); state->lease.frominfo = 1; if (state->new == NULL && @@ -3554,7 +4242,8 @@ dhcp_start1(void *arg) } if (state->offer == NULL || !IS_DHCP(state->offer)) - dhcp_discover(ifp); + //eloop_timeout_add_tv(ifp->ctx->eloop, &tv, callback, dhcp_discover,ifp); + dhcp_discover(ifp); else dhcp_reboot(ifp); } @@ -3563,6 +4252,7 @@ void dhcp_start(struct interface *ifp) { struct timespec tv; + struct dhcp_state *state; if (!(ifp->options->options & DHCPCD_IPV4)) return; @@ -3606,6 +4296,56 @@ dhcp_start(struct interface *ifp) return; } + if (!(ifp->options->options & DHCPCD_IPV4)) + return; + + /* Listen on *.*.*.*:bootpc so that the kernel never sends an + * ICMP port unreachable message back to the DHCP server */ + if (ifp->ctx->udp_fd == -1) { + ifp->ctx->udp_fd = dhcp_openudp(NULL); + if (ifp->ctx->udp_fd == -1) { + /* Don't log an error if some other process + * is handling this. */ + if (errno != EADDRINUSE) + logger(ifp->ctx, LOG_ERR, + "%s: dhcp_openudp: %m", __func__); + } else + eloop_event_add(ifp->ctx->eloop, + ifp->ctx->udp_fd, dhcp_handleudp, ifp->ctx); + } + + if (dhcp_init(ifp) == -1) { + logger(ifp->ctx, LOG_ERR, "%s: dhcp_init: %m", ifp->name); + return; + } + + state = D_STATE(ifp); + free(state->offer); + state->offer = NULL; + + if (state->arping_index != -1 && + state->arping_index < ifp->options->arping_len) { + struct arp_state *astate; + + astate = arp_new(ifp, NULL, NULL, NULL); + if (astate) { + astate->probed_cb = dhcp_arp_probed; + astate->conflicted_cb = dhcp_arp_conflicted; + dhcp_arp_probed(astate); + } + return; + } + + /* Initiate DNA */ + //logger(ifp->ctx, LOG_DEBUG, "%s: DNA Check", ifp->name); + if (ifp->options->options & DHCPCD_DNA) { + logger(ifp->ctx, LOG_DEBUG, "%s: DNA Option Present", ifp->name); + state->dna_lease_len = read_dna_leases(ifp, &state->dna_leases); + if (state->dna_leases) { + dhcp_dna_addresses(ifp); + } + } + tv.tv_sec = DHCP_MIN_DELAY; tv.tv_nsec = (suseconds_t)arc4random_uniform( (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * NSEC_PER_SEC); @@ -3620,6 +4360,13 @@ dhcp_start(struct interface *ifp) void dhcp_abort(struct interface *ifp) { +#ifdef ARPING + struct dhcp_state *state; + + state = D_STATE(ifp); + if (state != NULL) + state->arping_index = -1; +#endif eloop_timeout_delete(ifp->ctx->eloop, dhcp_start1, ifp); } @@ -97,7 +97,7 @@ enum DHO { DHO_LEASETIME = 51, DHO_OPTSOVERLOADED = 52, DHO_MESSAGETYPE = 53, - DHO_SERVERID = 54, + DHO_SERVERID = 54, /* RFC 2132: Piers */ DHO_PARAMETERREQUESTLIST = 55, DHO_MESSAGE = 56, DHO_MAXMESSAGESIZE = 57, @@ -160,8 +160,8 @@ struct bootp { uint16_t flags; /* such as broadcast flag */ uint32_t ciaddr; /* (previously allocated) client IP */ uint32_t yiaddr; /* 'your' client IP address */ - uint32_t siaddr; /* should be zero in client's messages */ - uint32_t giaddr; /* should be zero in client's messages */ + uint32_t siaddr; /* Server IP(should be zero in client's messages)*/ + uint32_t giaddr; /* Relay IP (should be zero in client's messages)*/ uint8_t chaddr[BOOTP_CHADDR_LEN]; /* client's hardware address */ uint8_t sname[BOOTP_SNAME_LEN]; /* server host name */ uint8_t file[BOOTP_FILE_LEN]; /* boot file name */ @@ -179,6 +179,9 @@ struct dhcp_lease { struct in_addr server; uint8_t frominfo; uint32_t cookie; + unsigned char hwaddr[HWADDR_LEN]; //Piers MAC addr of DHCP server + struct bootp *bootp; + size_t bootp_len; }; enum DHS { @@ -195,6 +198,12 @@ enum DHS { DHS_RELEASE }; +/*struct dna_lease { + struct bootp *lease; + size_t lease_len; + unsigned char shaddr[HWADDR_LEN]; * +Piers:server's hardware address */ +//}; + struct dhcp_state { enum DHS state; struct bootp *sent; @@ -212,15 +221,20 @@ struct dhcp_state { uint32_t xid; int socket; + /*Piers: DNA Leases */ + struct dhcp_lease *dna_leases; + size_t dna_lease_len; + struct bootp *dna_matched_lease; + int raw_fd; struct ipv4_addr *addr; uint8_t added; - char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDLEN * 4)]; + char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDLEN * 4) + BOOTP_CHADDR_LEN]; struct timespec started; unsigned char *clientid; struct authstate auth; - size_t arping_index; + ssize_t arping_index; }; #define D_STATE(ifp) \ @@ -230,6 +244,7 @@ struct dhcp_state { #define D_STATE_RUNNING(ifp) \ (D_CSTATE((ifp)) && D_CSTATE((ifp))->new && D_CSTATE((ifp))->reason) +/* Check for the DHCP 'magic cookie' */ #define IS_DHCP(b) ((b)->vend[0] == 0x63 && \ (b)->vend[1] == 0x82 && \ (b)->vend[2] == 0x53 && \ diff --git a/dhcpcd.conf b/dhcpcd.conf index aeba3567..2692c54e 100644 --- a/dhcpcd.conf +++ b/dhcpcd.conf @@ -36,3 +36,12 @@ require dhcp_server_identifier # Generate Stable Private IPv6 Addresses instead of hardware based ones slaac private + +# Enable DNA functionality +dna + +# Enable DNA Privacy: Random Address type 1 +dna_random 1 + +# Enable DNA Privacy: Dummy Address type 1 +dna_dummy 1 @@ -575,6 +575,7 @@ eloop_q_timeout_delete(struct eloop *eloop, int queue, assert(eloop != NULL); + //Piers: Delete timeout if it matches OR is called with NULL TAILQ_FOREACH_SAFE(t, &eloop->timeouts, next, tt) { if ((queue == 0 || t->queue == queue) && t->arg == arg && @@ -474,7 +474,7 @@ eexit: ssize_t if_sendraw(__unused const struct interface *ifp, int fd, uint16_t protocol, - const void *data, size_t len) + const void *data, size_t len, const unsigned char *hwaddr) { struct iovec iov[2]; struct ether_header hw; @@ -492,7 +492,7 @@ if_sendraw(__unused const struct interface *ifp, int fd, uint16_t protocol, /* BPF requires that we read the entire buffer. * So we pass the buffer in the API so we can loop on >1 packet. */ ssize_t -if_readraw(struct interface *ifp, int fd, void *data, size_t len, int *flags) +if_readraw(struct interface *ifp, int fd, void *data, size_t len, int *flags, unsigned char *hwaddr) { struct bpf_hdr packet; ssize_t bytes; @@ -86,7 +86,7 @@ int if_getssid_wext(const char *ifname, uint8_t *ssid); #define bpf_insn sock_filter #define BPF_SKIPTYPE -#define BPF_ETHCOOK -ETH_HLEN +//#define BPF_ETHCOOK -ETH_HLEN #define BPF_WHOLEPACKET 0x0fffffff /* work around buggy LPF filters */ #include "bpf-filter.h" @@ -1235,12 +1235,13 @@ if_openraw(struct interface *ifp, uint16_t protocol) struct sockaddr_storage ss; } su; struct sock_fprog pf; + #ifdef PACKET_AUXDATA int n; #endif #define SF SOCK_CLOEXEC | SOCK_NONBLOCK - if ((s = xsocket(PF_PACKET, SOCK_DGRAM | SF, htons(protocol))) == -1) + if ((s = xsocket(PF_PACKET, SOCK_RAW | SF , htons(protocol))) == -1) return -1; #undef SF @@ -1278,13 +1279,26 @@ eexit: ssize_t if_sendraw(const struct interface *ifp, int fd, uint16_t protocol, - const void *data, size_t len) + const void *data, size_t len, const unsigned char *hwaddr) { union sockunion { struct sockaddr sa; struct sockaddr_ll sll; struct sockaddr_storage ss; } su; + struct ether_header ehdr; + struct iovec iov[2] = {{ + .iov_base = &ehdr, + .iov_len = sizeof(ehdr), + },{ + .iov_base = (void*)data, + .iov_len = len, + }}; + struct msghdr msg = { + .msg_iov = iov, + .msg_iovlen = 2, + }; + memset(&su, 0, sizeof(su)); su.sll.sll_family = AF_PACKET; @@ -1298,26 +1312,39 @@ if_sendraw(const struct interface *ifp, int fd, uint16_t protocol, * Ugly as sin, but it works. */ /* coverity[buffer_size] */ /* coverity[overrun-buffer-arg] */ + //Piers: Set dest_addr as broadcast address memcpy(&su.sll.sll_addr, &ipv4_bcast_addr, sizeof(ipv4_bcast_addr)); } else + if (!hwaddr) // TODO: Handle IPoIB memset(&su.sll.sll_addr, 0xff, ifp->hwlen); + else + memcpy(&su.sll.sll_addr, hwaddr, ifp->hwlen); - return sendto(fd, data, len, 0, &su.sa, sizeof(su.sll)); + memcpy(&ehdr.ether_dhost, &su.sll.sll_addr, ifp->hwlen); + memcpy(&ehdr.ether_shost, ifp->hwaddr, ifp->hwlen); + ehdr.ether_type=htons(protocol); + return sendmsg(fd, &msg, 0); } ssize_t if_readraw(__unused struct interface *ifp, int fd, - void *data, size_t len, int *flags) + void *data, size_t len, int *flags, unsigned char *hwaddr) { - struct iovec iov = { + struct ether_header ehdr; + struct iovec iov[2] = {{ + .iov_base = &ehdr, + .iov_len = sizeof(ehdr), + },{ .iov_base = data, .iov_len = len, - }; + }}; struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, + .msg_iov = iov, + .msg_iovlen = 2, }; + + #ifdef PACKET_AUXDATA unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; struct cmsghdr *cmsg; @@ -1350,6 +1377,17 @@ if_readraw(__unused struct interface *ifp, int fd, } #endif } + +/* printf("bytes recv:%lu; ether_dhost",bytes); + for (int i=0; i<ETH_ALEN; i++) + printf(":%02x",ehdr.ether_dhost[i]); + printf(", ether_shost"); + for (int i=0; i<ETH_ALEN; i++) + printf(":%02x",ehdr.ether_shost[i]); + printf("\n");*/ + + if (hwaddr) + memcpy(hwaddr, ehdr.ether_shost, ETH_ALEN); return bytes; } diff --git a/if-options.c b/if-options.c index 3334d413..91380377 100644 --- a/if-options.c +++ b/if-options.c @@ -101,6 +101,11 @@ #define O_NODELAY O_BASE + 44 #define O_INFORM6 O_BASE + 45 #define O_LASTLEASE_EXTEND O_BASE + 46 +#define O_DNA O_BASE + 47 +#define O_DNA_ORD O_BASE + 48 +#define O_DNA_DUM O_BASE + 49 +#define O_DNA_PRAN O_BASE + 50 +#define O_DNA_GURL O_BASE + 51 const struct option cf_options[] = { {"background", no_argument, NULL, 'b'}, @@ -200,6 +205,11 @@ const struct option cf_options[] = { {"nodelay", no_argument, NULL, O_NODELAY}, {"noup", no_argument, NULL, O_NOUP}, {"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND}, + {"dna", no_argument, NULL, O_DNA}, + {"dna_random", required_argument, NULL, O_DNA_ORD}, + {"dna_dummy", required_argument, NULL, O_DNA_DUM}, + {"dna_preanalysis", required_argument, NULL, O_DNA_PRAN}, + {"dna_geourl", required_argument, NULL, O_DNA_GURL}, {NULL, 0, NULL, '\0'} }; @@ -933,7 +943,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, if (ifname == NULL) ctx->ifav = splitv(ctx, &ctx->ifac, ctx->ifav, arg); break; - case 'A': + case 'A': /* noarp */ ifo->options &= ~DHCPCD_ARP; /* IPv4LL requires ARP */ ifo->options &= ~DHCPCD_IPV4LL; @@ -1252,7 +1262,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, if (parse_addr(ctx, &addr, NULL, arg) != 0) return -1; naddr = realloc(ifo->arping, - sizeof(in_addr_t) * (ifo->arping_len + 1)); + sizeof(in_addr_t) * ((size_t)ifo->arping_len + 1)); if (naddr == NULL) { logger(ctx, LOG_ERR, "%s: %m", __func__); return -1; @@ -2133,6 +2143,42 @@ err_sla: case O_LASTLEASE_EXTEND: ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND; break; + case O_DNA: + ifo->options |= DHCPCD_DNA; + break; + case O_DNA_ORD: + ARG_REQUIRED; + ifo->dna_ord = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); + if (e) { + logger(ctx, LOG_ERR, "failed to convert DNA order %s", arg); + return -1; + } + break; + case O_DNA_DUM: + ARG_REQUIRED; + ifo->dna_dum = (int)strtoi(arg, NULL, 0, -1, INT32_MAX, &e); + if (e) { + logger(ctx, LOG_ERR, "failed to convert DNA dummy %s", arg); + return -1; + } + break; + case O_DNA_PRAN: + ARG_REQUIRED; + ifo->dna_pran = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); + if (e) { + logger(ctx, LOG_ERR, "failed to convert DNA preanalysis %s", arg); + return -1; + } + break; + case O_DNA_GURL: + ARG_REQUIRED; + ifo->dna_gurl = (char*)malloc(strlen(arg)*sizeof(char)); + if (ifo->dna_gurl == NULL) { + logger(ctx, LOG_ERR, "%s: Failed Malloc for GeoURL %m", __func__); + return -1; + } + strcpy(ifo->dna_gurl, arg); + break; default: return 0; } @@ -2420,6 +2466,7 @@ read_config(struct dhcpcd_ctx *ctx, /* Parse our options file */ fp = fopen(ctx->cffile, "r"); + logger(ctx, LOG_DEBUG, "Using Config file: %s", ctx->cffile); if (fp == NULL) { if (strcmp(ctx->cffile, CONFIG)) logger(ctx, LOG_ERR, "fopen `%s': %m", ctx->cffile); diff --git a/if-options.h b/if-options.h index a0be326a..b4214718 100644 --- a/if-options.h +++ b/if-options.h @@ -115,6 +115,7 @@ #define DHCPCD_INITIAL_DELAY (1ULL << 58) #define DHCPCD_PRINT_PIDFILE (1ULL << 59) #define DHCPCD_ONESHOT (1ULL << 60) +#define DHCPCD_DNA (1ULL << 61) #define DHCPCD_NODROP (DHCPCD_EXITING | DHCPCD_PERSISTENT) @@ -195,7 +196,7 @@ struct if_options { in_addr_t *blacklist; size_t whitelist_len; in_addr_t *whitelist; - size_t arping_len; + ssize_t arping_len; in_addr_t *arping; char *fallback; @@ -215,6 +216,11 @@ struct if_options { size_t vivso_override_len; struct auth auth; + + int dna_ord; + int dna_dum; + int dna_pran; + char* dna_gurl; }; struct if_options *default_config(struct dhcpcd_ctx *); @@ -957,7 +957,7 @@ failed1: ssize_t if_sendraw(const struct interface *cifp, int fd, __unused uint16_t protocol, - const void *data, size_t len) + const void *data, size_t len, const unsigned char *hwaddr) { struct dl_if *di; int r; @@ -971,7 +971,7 @@ if_sendraw(const struct interface *cifp, int fd, __unused uint16_t protocol, ssize_t if_readraw(struct interface *ifp, int fd, - void *data, size_t len, int *flags) + void *data, size_t len, int *flags, unsigned char *hwaddr) { struct dl_if *di; int r; @@ -142,8 +142,8 @@ int if_handlelink(struct dhcpcd_ctx *); extern const char *if_pfname; int if_openraw(struct interface *, uint16_t); ssize_t if_sendraw(const struct interface *, int, uint16_t, - const void *, size_t); -ssize_t if_readraw(struct interface *, int, void *, size_t, int *); + const void *, size_t, const unsigned char *); +ssize_t if_readraw(struct interface *, int, void *, size_t, int *, unsigned char *); void if_closeraw(struct interface *, int); int if_address(unsigned char, const struct ipv4_addr *); @@ -1195,7 +1195,7 @@ ipv4_applyaddr(void *arg) if (ifo->options & DHCPCD_ARP) { struct arp_state *astate; - if ((astate = arp_new(ifp, &state->addr->addr)) != NULL) + if ((astate = arp_new(ifp, &state->addr->addr, NULL, NULL)) != NULL) arp_announce(astate); } if (state->state == DHS_BOUND) { @@ -244,6 +244,12 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg) ifp = astate->iface; state = IPV4LL_STATE(ifp); assert(state != NULL); + if (state->addr == NULL) { + logger(ifp->ctx, LOG_WARNING, + "%s: IPv4LL %d No addr configured", + ifp->name, DEFEND_INTERVAL); + return; + } assert(state->addr != NULL); fail = 0; @@ -283,7 +289,7 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg) "%s: IPv4LL %d second defence failed for %s", ifp->name, DEFEND_INTERVAL, state->addr->saddr); else if (arp_request(ifp, - state->addr->addr.s_addr, state->addr->addr.s_addr) == -1) + state->addr->addr.s_addr, state->addr->addr.s_addr, NULL) == -1) logger(ifp->ctx, LOG_ERR, "%s: arp_request: %m", __func__); else { @@ -369,7 +375,7 @@ ipv4ll_start(void *arg) setstate(ifp->ctx->randomstate); } - if ((astate = arp_new(ifp, NULL)) == NULL) + if ((astate = arp_new(ifp, NULL, NULL, NULL)) == NULL) return; state->arp = astate; |
