From a9df523f76f43a38bd53b4232b9cfd4c16869e71 Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Wed, 17 Jun 2026 11:07:05 -0300 Subject: [PATCH] assorted patches --- .github/workflows/nightly.yml | 1 + .github/workflows/quicktest.yml | 1 + mongoose.c | 743 ++++++++++++++++++++---------- mongoose.h | 76 +-- src/dns.c | 4 +- src/drivers/cyw.c | 2 +- src/drivers/rw612.c | 8 +- src/drivers/tms570.c | 5 +- src/drivers/w5100.c | 2 +- src/fmt.c | 19 +- src/fs.c | 13 +- src/fs.h | 2 +- src/fs_fat.c | 22 +- src/fs_posix.c | 22 +- src/http.c | 47 +- src/l2_eth.c | 2 +- src/l2_ppp.c | 14 +- src/mqtt.c | 38 +- src/net_builtin.c | 61 ++- src/net_builtin.h | 1 + src/printf.c | 28 ++ src/printf.h | 4 +- src/sock.c | 4 +- src/ssi.c | 11 +- src/tls_aes128.c | 1 + src/tls_builtin.c | 357 ++++++++------ src/tls_mbed.c | 3 +- src/tls_openssl.c | 15 +- src/tls_rsa.c | 65 +++ src/tls_rsa.h | 1 + test/certs/ca.crt | 15 +- test/certs/generate.sh | 7 +- test/unit_test.c | 233 +++++++--- tutorials/mqtt/mqtt-server/main.c | 5 +- 34 files changed, 1240 insertions(+), 592 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 4c2bd050..42ce55dd 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -262,6 +262,7 @@ jobs: name: tutorials_win ${{ matrix.ssl }} steps: - uses: actions/checkout@v4 + with: { fetch-depth: 2 } # - uses: egor-tensin/setup-mingw@v2 # with: # platform: x64 diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index f7fb6873..95e6927d 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -114,6 +114,7 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 + with: { fetch-depth: 2 } # - uses: egor-tensin/setup-mingw@v2 # with: # platform: x64 diff --git a/mongoose.c b/mongoose.c index 7bd165e1..e37cdaf6 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1800,8 +1800,8 @@ static void sendnsreq(struct mg_connection *c, struct mg_str *name, int ms, struct dns_data *reqs = (struct dns_data *) c->mgr->active_dns_requests; uint16_t id; mg_random(&id, sizeof(uint16_t)); - // TODO(): traverse reqs and check id != reqs->txnid; repeat otherwise - if (reqs != NULL) id = (uint16_t) (reqs->txnid + 1); // no collision + if (reqs != NULL) // no seq, no collision for upto 256 in-flight requests + id = (uint16_t) (reqs->txnid + (id & 0xFF) + 1); d->txnid = id; d->next = reqs; c->mgr->active_dns_requests = d; @@ -2448,16 +2448,17 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width, bool tz) { while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; // printf(" --> %g %d %g %g\n", saved, e, t, mul); - if (tz && e >= width && width > 1) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); + if (tz && (e >= width || e <= -width) && width > 1) { + char exp[6]; + int ne; + n = (int) mg_dtoa(buf + s, sizeof(buf) - (size_t) s, saved / mul, width, tz); // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); - n += addexp(buf + s + n, e, '+'); - return mg_snprintf(dst, dstlen, "%.*s", n, buf); - } else if (tz && e <= -width && width > 1) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); - // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); - n += addexp(buf + s + n, -e, '-'); - return mg_snprintf(dst, dstlen, "%.*s", n, buf); + ne = addexp(exp, e < 0 ? -e : e, e < 0 ? '-' : '+'); + if (s + n + ne >= (int) sizeof(buf)) + n = (int) sizeof(buf) - s - ne - 1; + memcpy(buf + s + n, exp, (size_t) ne); + n += ne; + return mg_snprintf(dst, dstlen, "%.*s", s + n, buf); } else { int targ_width = width; for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { @@ -2663,17 +2664,18 @@ bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, size_t len) { bool result = false; struct mg_fd *fd; - char tmp[MG_PATH_MAX]; - mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); - if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { + char tmp[MG_PATH_MAX], rnd[10]; + size_t path_len = mg_snprintf(tmp, sizeof(tmp), "%s..%s", path, + mg_random_str(rnd, sizeof(rnd))); + if (path_len < sizeof(tmp) && + (fd = mg_fs_open(fs, tmp, MG_FS_WRITE | MG_FS_EXCL)) != NULL) { result = fs->wr(fd->fd, buf, len) == len; mg_fs_close(fd); if (result) { fs->rm(path); - fs->mv(tmp, path); - } else { - fs->rm(tmp); + result = fs->mv(tmp, path); } + fs->rm(tmp); } return result; } @@ -2717,6 +2719,7 @@ bool mg_fs_ls(struct mg_fs *fs, const char *path, char *buf, size_t len) { + #if MG_ENABLE_FATFS #include @@ -2785,17 +2788,22 @@ static void ff_list(const char *dir, void (*fn)(const char *, void *), } static void *ff_open(const char *path, int flags) { - FIL f; + FIL *fp = NULL; unsigned char mode = FA_READ; - if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND; - if (f_open(&f, path, mode) == 0) { - FIL *fp; - if ((fp = mg_calloc(1, sizeof(*fp))) != NULL) { - memcpy(fp, &f, sizeof(*fp)); - return fp; + if (flags & MG_FS_WRITE) { + mode |= FA_WRITE; + if (flags & MG_FS_EXCL) { + mode |= FA_OPEN_ALWAYS | FA_OPEN_APPEND; + } else { + mode |= FA_CREATE_NEW; } } - return NULL; + if ((fp = mg_calloc(1, sizeof(*fp))) != NULL && + f_open(fp, path, mode) != FR_OK) { + mg_free(fp); + fp = NULL; + } + return fp; } static void ff_close(void *fp) { @@ -3078,6 +3086,7 @@ DIR *opendir(const char *name) { DIR *d = NULL; wchar_t wpath[MAX_PATH]; DWORD attrs; + size_t n; if (name == NULL) { SetLastError(ERROR_BAD_ARGUMENTS); @@ -3087,9 +3096,16 @@ DIR *opendir(const char *name) { to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); attrs = GetFileAttributesW(wpath); if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { - (void) wcscat(wpath, L"\\*"); - d->handle = FindFirstFileW(wpath, &d->info); - d->result.d_name[0] = '\0'; + n = wcslen(wpath); + if (n <= (sizeof(wpath) / sizeof(wpath[0])) - 3) { + (void) wcscat(wpath, L"\\*"); + d->handle = FindFirstFileW(wpath, &d->info); + d->result.d_name[0] = '\0'; + } else { + mg_free(d); + d = NULL; + SetLastError(ERROR_BUFFER_OVERFLOW); + } } else { mg_free(d); d = NULL; @@ -3151,13 +3167,17 @@ static void p_list(const char *dir, void (*fn)(const char *, void *), static void *p_open(const char *path, int flags) { #if MG_ARCH == MG_ARCH_WIN32 - const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; + const char *mode = flags == MG_FS_READ ? "rb" + : (flags & MG_FS_EXCL) ? "wxb" + : "a+b"; wchar_t b1[MG_PATH_MAX], b2[10]; MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0])); return (void *) _wfopen(b1, b2); #else - const char *mode = flags == MG_FS_READ ? "rbe" : "a+be"; // e for CLOEXEC + const char *mode = flags == MG_FS_READ ? "rbe" + : (flags & MG_FS_EXCL) ? "wxbe" + : "a+be"; // e for CLOSEXEC return (void *) fopen(path, mode); #endif } @@ -3313,14 +3333,14 @@ size_t mg_http_next_multipart(struct mg_str body, size_t ofs, if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0); // Skip boundary - while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++; + while (b + 2 < max && !(s[b] == '\r' && s[b + 1] == '\n')) b++; if (b <= ofs || b + 2 >= max) return 0; // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s)); // Skip headers h1 = h2 = b + 2; for (;;) { - while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++; + while (h2 + 2 < max && !(s[h2] == '\r' && s[h2 + 1] == '\n')) h2++; if (h2 == h1) break; if (h2 + 2 >= max) return 0; // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1])); @@ -3568,7 +3588,10 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { if (!mg_http_parse_headers(s, end, hm->headers, sizeof(hm->headers) / sizeof(hm->headers[0]))) return -1; // error when parsing - if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { + cl = mg_http_get_header(hm, "Content-Length"); + if (cl != NULL && mg_http_get_header(hm, "Transfer-Encoding") != NULL) + return -1; // cannot contain both CL and TE + if (cl != NULL) { if (mg_to_size_t(*cl, &hm->body.len) == false) return -1; hm->message.len = (size_t) req_len + hm->body.len; } @@ -3924,6 +3947,24 @@ struct printdirentrydata { }; #if MG_ENABLE_DIRLIST +// Print file name, escaping HTML chars +static size_t html_esc(void (*fn)(char, void *), void *arg, va_list *ap) { + const char *s = va_arg(*ap, const char *); + size_t i, len = 0; + for (i = 0; s[i] != '\0'; i++) { + if (s[i] == '<') { + len += mg_xprintf(fn, arg, "%s", "<"); + } else if (s[i] == '>') { + len += mg_xprintf(fn, arg, "%s", ">"); + } else if (s[i] == '&') { + len += mg_xprintf(fn, arg, "%s", "&"); + } else { + len += mg_xprintf(fn, arg, "%c", s[i]); + } + } + return len; +} + static void printdirentry(const char *name, void *userdata) { struct printdirentrydata *d = (struct printdirentrydata *) userdata; struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs; @@ -3957,9 +3998,9 @@ static void printdirentry(const char *name, void *userdata) { #endif n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); mg_printf(d->c, - " %s%s" + " %M%s" "%s%s\n", - n, path, slash, name, slash, (unsigned long) t, mod, + n, path, slash, html_esc, name, slash, (unsigned long) t, mod, flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz); } } @@ -4004,22 +4045,21 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, opts->extra_headers == NULL ? "" : opts->extra_headers); off = c->send.len; // Start of body mg_printf(c, - "Index of %.*s%s%s" + "Index of %M%s%s" "" - "

Index of %.*s

" + "

Index of %M

" "" "" "" "" "\n", - (int) uri.len, uri.buf, sort_js_code, sort_js_code2, (int) uri.len, - uri.buf); + mg_print_html_esc, (int) uri.len, uri.buf, sort_js_code, sort_js_code2, + mg_print_html_esc, (int) uri.len, uri.buf); mg_printf(c, "%s", " " "\n"); - fs->ls(dir, printdirentry, &d); mg_printf(c, "" @@ -4189,7 +4229,8 @@ struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { p++; // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.buf, (int) v.len, // v.buf, (int) (p - b), b)); - return stripquotes(mg_str_n(b, (size_t) (p - b + q))); + return stripquotes(mg_str_n(b, + (size_t) (p - b + (q && p < x && *p == '"' ? 1 : 0)))); } } return mg_str_n(NULL, 0); @@ -4346,7 +4387,7 @@ static int skip_chunk(const char *buf, int len, int *pl, int *dl) { while (i < len && is_hex_digit(buf[i])) i++; if (i == 0) return -1; // Error, no length specified if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big - if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error + if (len < i + 2 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false) return -1; // Decode chunk length, overflow if (n < 0) return -1; // Error. TODO(): some checks now redundant @@ -4390,7 +4431,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); } is_http_1_0 = - hm.proto.len > 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0; + hm.proto.len == 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0; // HTTP/1.0 does not use "Transfer-Encoding: chunked" if (!is_http_1_0 && (te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) { @@ -5150,7 +5191,7 @@ void mg_l2_eth_init(struct mg_tcpip_if *ifp) { MG_INFO( ("MAC not set. Generated random: %M", mg_print_mac, l2addr->addr.mac)); } - ifp->mtu = 1500; + ifp->l2mtu = 1500; ifp->framesize = 1540; } @@ -5412,7 +5453,7 @@ static uint8_t s_state = MG_PPPoE_ST_DISC; static uint16_t s_id; void mg_l2_ppp_init(struct mg_tcpip_if *ifp) { - ifp->mtu = 1500; + ifp->l2mtu = 1500; ifp->framesize = 1500 + sizeof(struct ppp) + sizeof(struct hdlc_); } @@ -5420,7 +5461,7 @@ extern void mg_l2_eth_init(struct mg_tcpip_if *); void mg_l2_pppoe_init(struct mg_tcpip_if *ifp) { mg_l2_eth_init(ifp); - ifp->mtu = ifp->mtu - (uint16_t) (sizeof(struct pppoe) + + ifp->l2mtu = ifp->l2mtu - (uint16_t) (sizeof(struct pppoe) + sizeof(struct ppp)); // 1500 --> 1492 } @@ -5589,8 +5630,8 @@ static void ppp_handle_lcp(struct mg_tcpip_if *ifp, uint8_t *lcpp, static bool find_opt(const uint8_t opt, const uint8_t optlen, const uint8_t *opts, size_t optslen, uint8_t *dest) { uint8_t *p = (uint8_t *) opts; - while (optslen >= 2) { // parse options for requested one - if (p[1] > optslen) return false; // truncated / malformed + while (optslen >= 2) { // parse options for requested one + if (p[1] > optslen || p[1] < 2) return false; // truncated / malformed if (p[0] == opt && p[1] == optlen) { memcpy(dest, p + 2, optlen - 2); return true; @@ -5611,6 +5652,7 @@ static void ppp_handle_ipcp(struct mg_tcpip_if *ifp, uint8_t *ipcpp, if (ipcpsz < sizeof(*ipcp)) return; id = ipcp->id; len = mg_ntohs(ipcp->len); + if (len > ipcpsz) return; switch (ipcp->code) { case MG_PPP_IPCP_CFG_REQ: MG_VERBOSE(("got IPCP config request, acknowledging...")); @@ -5761,8 +5803,9 @@ static bool ppp_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto, size_t msglen; MG_DEBUG(("unknown %u-byte PPP frame with proto 0x%04x:", pay->len + sizeof(*ppp), mg_ntohs(ppp->proto))); - if (mg_log_level >= MG_LL_DEBUG) mg_hexdump(ppp, sizeof(*ppp) + 20); - if (!s_lcpup) return false; // RFC-1661 5.7: must reject on link up + if (mg_log_level >= MG_LL_DEBUG) + mg_hexdump(ppp, pay->len > 14 ? 16 : pay->len + sizeof(*ppp)); + if (!s_lcpup) return false; // RFC-1661 5.7: must reject on link down if (pay->len > (size_t) (ifp->mtu - 20)) pay->len = (size_t) (ifp->mtu - 20); // truncate to some safe limit rej.code = MG_PPP_LCP_REJECT; @@ -6926,12 +6969,15 @@ static bool mg_send_mqtt_properties(struct mg_connection *c, size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, size_t ofs) { - uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs; - uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len; + uint8_t *props = (uint8_t *) msg->dgram.buf + msg->props_start; + uint8_t *props_end = props + msg->props_size; + uint8_t *i = props + ofs; size_t new_pos = ofs, len; - - if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size || (i + 1) >= end) - return 0; + + if (msg->props_start > msg->dgram.len || + msg->props_size > msg->dgram.len - msg->props_start || + ofs >= msg->props_size) + return 0; memset(prop, 0, sizeof(struct mg_mqtt_prop)); prop->id = i[0]; @@ -6939,49 +6985,50 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, switch (mqtt_prop_type_by_id(prop->id)) { case MQTT_PROP_TYPE_STRING_PAIR: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + if (i + 2 + prop->key.len > props_end) return 0; prop->key.buf = (char *) i + 2; i += 2 + prop->key.len; - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; - if (i + 2 + prop->val.len >= end) return 0; + if (i + 2 + prop->val.len > props_end) return 0; new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; break; case MQTT_PROP_TYPE_BYTE: - if (i + 1 >= end) return 0; + if (i + 1 > props_end) return 0; prop->iv = (uint8_t) i[0]; new_pos++; break; case MQTT_PROP_TYPE_SHORT: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); new_pos += sizeof(uint16_t); break; case MQTT_PROP_TYPE_INT: - if (i + 4 >= end) return 0; + if (i + 4 > props_end) return 0; prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | ((uint32_t) i[2] << 8) | i[3]; new_pos += sizeof(uint32_t); break; case MQTT_PROP_TYPE_STRING: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; - if (i + 2 + prop->val.len >= end) return 0; + if (i + 2 + prop->val.len > props_end) return 0; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_BINARY_DATA: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; - if (i + 2 + prop->val.len >= end) return 0; + if (i + 2 + prop->val.len > props_end) return 0; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_VARIABLE_INT: - len = decode_varint(i, (size_t) (end - i), &prop->iv); - if (i + len >= end) return 0; + len = decode_varint(i, (size_t) (props_end - i), &prop->iv); + if (i + len > props_end) return 0; new_pos = (len == 0) ? 0 : new_pos + len; break; default: @@ -8294,7 +8341,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { size_t plen = pkt->pay.len; if (!icmpcsum_ok(pkt->icmp, sizeof(struct icmp) + plen)) return; if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { - size_t l2_max_overhead = ifp->framesize - ifp->mtu; + size_t l2_max_overhead = ifp->framesize - ifp->l2mtu; size_t hlen = sizeof(struct ip) + sizeof(struct icmp); size_t room = ifp->tx.len - hlen - l2_max_overhead; uint8_t *l2addr; @@ -8326,9 +8373,9 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0, owner = 0; uint8_t msgtype = 0, state = ifp->state; // perform size check first, then access fields - uint8_t *p = pkt->dhcp->options, + uint8_t *p = (uint8_t *) pkt->pay.buf, *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len]; - if (end < p) return; // options are optional, check min header length + // min header length checked at payload calculation, options are optional if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; while (p + 1 < end && p[0] != 255) { // Parse options, get #1; RFC-2132 9 if (p[0] == 1 && p[1] == 4 && p + 6 < end) { // Mask, 3.3 @@ -8368,7 +8415,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (msgtype == 5) { // DHCPACK if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP uint64_t rand; - ifp->lease_expire = ifp->now + lease * 1000; + ifp->lease_expire = ifp->now + (uint64_t) lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, mg_l2_getaddr(ifp, pkt->l2), sizeof(ifp->gwmac)); @@ -8385,7 +8432,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (ifp->enable_req_sntp && sntp != 0) mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew - ifp->lease_expire = ifp->now + lease * 1000; + ifp->lease_expire = ifp->now + (uint64_t) lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4) } @@ -8395,11 +8442,11 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // Simple DHCP server that assigns a next IP address: ifp->ip + 1 static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint8_t *mac; - uint8_t op = 0, *p = pkt->dhcp->options, + uint8_t op = 0, *p = (uint8_t *) pkt->pay.buf, *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len]; // NOTE(): assumes Ethernet: htype=1 hlen=6, copy 6 bytes struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; - if (end < p) return; // options are optional, check min header length + // min header length checked at payload calculation, options are optional res.yiaddr = ifp->ip; ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 while (p + 1 < end && p[0] != 255) { // Parse options @@ -8491,14 +8538,16 @@ static void tx_ndp_na(struct mg_tcpip_if *ifp, uint8_t *l2_dst, static void onstate6change(struct mg_tcpip_if *ifp); static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) { - struct ndp_na *na = (struct ndp_na *) (pkt->icmp6 + 1); - uint8_t *opts = (uint8_t *) (na + 1); + struct ndp_na *na = (struct ndp_na *) pkt->pay.buf; + uint8_t *opts = (uint8_t *) (na + 1), *endp = opts + pkt->pay.len - sizeof(*na); + if (pkt->pay.len < (sizeof(*na) + 2)) return; // first 2 bytes in opts if ((na->res[0] & 0x40) == 0) return; // not "solicited" - if (*opts++ != 2) return; // no target hwaddr + if (*opts++ != 2) return; // no target hwaddr, must have MG_VERBOSE(("NDP NA resp from %M", mg_print_ip6, (char *) &na->addr)); if (MG_IP6MATCH(na->addr, ifp->gw6)) { // Got response for the GW NS request. Set ifp->gw6mac and IP6 -> READY uint8_t len = *opts++; // check valid hwaddr and get it + if ((opts + 8 * len - 2) > endp) return; // truncated if (!mg_l2_ip6get(ifp->l2type, ifp->gw6mac, opts, len)) return; ifp->gw6_ready = true; if (ifp->state6 == MG_TCPIP_STATE_IP) { @@ -8510,6 +8559,7 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (c != NULL && c->is_arplooking) { struct connstate *s = (struct connstate *) (c + 1); uint8_t len = *opts++; // check valid hwaddr and get it + if ((opts + 8 * len - 2) > endp) return; // truncated if (!mg_l2_ip6get(ifp->l2type, s->mac, opts, len)) return; MG_DEBUG(("%lu NDP resolved %M -> %M", c->id, mg_print_ip6, &c->rem.addr.ip6, mg_print_l2addr, ifp->l2type, s->mac)); @@ -8521,15 +8571,17 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) { // Neighbor Solicitation, 4.3 static void rx_ndp_ns(struct mg_tcpip_if *ifp, struct pkt *pkt) { + struct ndp_na *ns = (struct ndp_na *) pkt->pay.buf; // struct ndp_ns = ndp_na uint64_t target[2]; - if (pkt->pay.len < sizeof(target)) return; - memcpy(target, pkt->pay.buf + 4, sizeof(target)); + if (pkt->pay.len < (sizeof(*ns) + 2)) return; // first 2 bytes in opts + memcpy(target, ns->addr, sizeof(target)); if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) { uint64_t req[2]; // requester address uint8_t l2[sizeof(struct mg_l2addr)]; - uint8_t len, *opts = (uint8_t *) pkt->pay.buf + 20; + uint8_t len, *opts = (uint8_t *) (ns + 1), *endp = opts + pkt->pay.len - sizeof(*ns); if (*opts++ != 1) return; // no requester hwaddr (source) len = *opts++; // check valid hwaddr and get it + if ((opts + 8 * len - 2) > endp) return; // truncated if (!mg_l2_ip6get(ifp->l2type, l2, opts, len)) return; req[0] = pkt->ip6->src[0], req[1] = pkt->ip6->src[1]; // align to 64-bit tx_ndp_na(ifp, l2, target, req, true, ifp->mac); @@ -8625,15 +8677,15 @@ static bool fill_global(struct mg_tcpip_if *ifp, uint8_t *prefix, // Router Advertisement, 4.2 static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { - if (pkt->pay.len < 12) return; - struct ndp_ra *ra = (struct ndp_ra *) (pkt->icmp6 + 1); + struct ndp_ra *ra = (struct ndp_ra *) pkt->pay.buf; uint8_t *opts = (uint8_t *) (ra + 1); - size_t opt_left = pkt->pay.len - 12; + size_t opt_left = pkt->pay.len - sizeof(*ra); bool gotl2addr = false, gotprefix = false, changed = false; uint8_t l2[sizeof(struct mg_l2addr)]; uint32_t mtu = 0; uint8_t *prefix, prefix_len; + if (pkt->pay.len < sizeof(*ra)) return; if (ifp->state6 == MG_TCPIP_STATE_UP) { MG_DEBUG(("Received NDP RA")); // fill gw6 address // parse options @@ -8646,8 +8698,9 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (!mg_l2_ip6get(ifp->l2type, l2, opts + 2, len)) break; gotl2addr = true; } else if (type == 5 && length >= 8) { - // process MTU if available + // process MTU if available, ignore if it smells mtu = MG_LOAD_BE32(opts + 4); + if (mtu < 1280 || mtu > ifp->l2mtu) mtu = 0; // RFC-8200, minimum MTU } else if (type == 3 && length >= 32) { // process prefix, 4.6.2 uint8_t pfx_flags = opts[3]; // L=0x80, A=0x40 @@ -8701,7 +8754,7 @@ static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint64_t target[2]; target[0] = pkt->ip6->dst[0], target[1] = pkt->ip6->dst[1]; if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) { - size_t l2_max_overhead = ifp->framesize - ifp->mtu; + size_t l2_max_overhead = ifp->framesize - ifp->l2mtu; size_t hlen = sizeof(struct ip6) + sizeof(struct icmp6); size_t room = ifp->tx.len - hlen - l2_max_overhead, plen = pkt->pay.len; struct mg_addr ips; @@ -8992,7 +9045,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn, static size_t trim_len(struct mg_connection *c, size_t len) { struct mg_tcpip_if *ifp = c->mgr->ifp; - size_t l2_max_overhead = ifp->framesize - ifp->mtu; + size_t l2_max_overhead = ifp->framesize - ifp->l2mtu; size_t ip_max_h_len = c->rem.is_ip6 ? 40 : 24; // we don't send options size_t tcp_max_h_len = 60 /* RFC-9293 3.7.1; RFC-6691 2 */, udp_h_len = 8; size_t max_headers_len = @@ -9379,11 +9432,13 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->udp->dport), (int) pkt->pay.len)); - if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68)) { + if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68) && + len >= offsetof(struct dhcp, options)) { pkt->dhcp = (struct dhcp *) (pkt->udp + 1); mkpay(pkt, &pkt->dhcp->options); rx_dhcp_client(ifp, pkt); - } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) { + } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67) && + len >= offsetof(struct dhcp, options)) { pkt->dhcp = (struct dhcp *) (pkt->udp + 1); mkpay(pkt, &pkt->dhcp->options); rx_dhcp_server(ifp, pkt); @@ -9421,19 +9476,24 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { next = pkt->ip6->next; nhdr = (uint8_t *) (pkt->ip6 + 1); while (loop) { + uint16_t hlen; switch (next) { case 0: // Hop-by-Hop 4.3 case 43: // Routing 4.4 case 60: // Destination Options 4.6 case 51: // Authentication RFC-4302 MG_INFO(("IPv6 extension header %d", (int) next)); + if (((uint32_t) len + 2) > plen) return; // nhdr[0, 1]; malformed next = nhdr[0]; - len += (uint16_t) (8 * (nhdr[1] + 1)); - nhdr += 8 * (nhdr[1] + 1); + hlen = (uint16_t) (8 * (nhdr[1] + 1)); + if (((uint32_t) len + hlen) > plen) return; // malformed + len += hlen; + nhdr += hlen; break; case 44: // Fragment 4.5 { struct mg_connection *c; + if (((uint32_t) len + 2) > plen) return; // nhdr[0, 1]; malformed if (nhdr[0] == 17) pkt->udp = (struct udp *) (pkt->pay.buf); if (nhdr[0] == 6) pkt->tcp = (struct tcp *) (pkt->pay.buf); c = getpeer(ifp->mgr, pkt, false); @@ -9448,7 +9508,6 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { break; } } - if (len >= plen) return; // There can be link padding, take payload length from IPv6 header - options pkt->pay.buf = (char *) nhdr; pkt->pay.len = plen - len; @@ -9726,6 +9785,7 @@ void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) { void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { // If L2 address is not set, make a random one; fill MTU mg_l2_init(ifp); + ifp->mtu = ifp->l2mtu; if (ifp->dhcp_name[0] == '\0') // If DHCP name is not set, use "mip" memcpy(ifp->dhcp_name, "mip", 4); @@ -12623,6 +12683,34 @@ size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) { return qcpy(out, arg, p, len); } +size_t mg_print_html_esc(void (*out)(char, void *), void *arg, va_list *ap) { + size_t i, n = 0; + int len = va_arg(*ap, int); + const char *s = va_arg(*ap, const char *); + for (i = 0; i < (size_t) len; i++) { + const char *esc = NULL; + switch (s[i]) { + // clang-format off + case '&': esc = "&"; break; + case '<': esc = "<"; break; + case '>': esc = ">"; break; + case '"': esc = """; break; + default: break; + // clang-format on + } + if (esc != NULL) { + while (*esc != '\0') { + out(*esc++, arg); + n++; + } + } else { + out(s[i], arg); + n++; + } + } + return n; +} + #ifdef MG_ENABLE_LINES #line 1 "src/queue.c" #endif @@ -13621,9 +13709,9 @@ void mg_getlocaddr(struct mg_connection *c, struct mg_addr *to, slen = tousa(to, &usa); if ((rc = connect(fd, &usa.sa, slen)) != 0) { mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); - return; + } else { + setlocaddr(fd, addr); } - setlocaddr(fd, addr); closesocket(fd); } @@ -14326,7 +14414,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { size_t len = 0; buf[0] = arg[0] = '\0'; while ((ch = fgetc(fp)) != EOF) { - if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { + if (intag && ch == '>' && len >= 2 && buf[len - 1] == '-' && buf[len - 2] == '-') { buf[len++] = (char) (ch & 0xff); buf[len] = '\0'; if (sscanf(buf, " %g %d %g %g\n", saved, e, t, mul); - if (tz && e >= width && width > 1) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); + if (tz && (e >= width || e <= -width) && width > 1) { + char exp[6]; + int ne; + n = (int) mg_dtoa(buf + s, sizeof(buf) - (size_t) s, saved / mul, width, tz); // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, n, buf); - n += addexp(buf + s + n, e, '+'); - return mg_snprintf(dst, dstlen, "%.*s", n, buf); - } else if (tz && e <= -width && width > 1) { - n = (int) mg_dtoa(buf, sizeof(buf), saved / mul, width, tz); - // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, n, buf); - n += addexp(buf + s + n, -e, '-'); - return mg_snprintf(dst, dstlen, "%.*s", n, buf); + ne = addexp(exp, e < 0 ? -e : e, e < 0 ? '-' : '+'); + if (s + n + ne >= (int) sizeof(buf)) + n = (int) sizeof(buf) - s - ne - 1; + memcpy(buf + s + n, exp, (size_t) ne); + n += ne; + return mg_snprintf(dst, dstlen, "%.*s", s + n, buf); } else { int targ_width = width; for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { diff --git a/src/fs.c b/src/fs.c index 6068ca21..fd9d7e6b 100644 --- a/src/fs.c +++ b/src/fs.c @@ -44,17 +44,18 @@ bool mg_file_write(struct mg_fs *fs, const char *path, const void *buf, size_t len) { bool result = false; struct mg_fd *fd; - char tmp[MG_PATH_MAX]; - mg_snprintf(tmp, sizeof(tmp), "%s..%d", path, rand()); - if ((fd = mg_fs_open(fs, tmp, MG_FS_WRITE)) != NULL) { + char tmp[MG_PATH_MAX], rnd[10]; + size_t path_len = mg_snprintf(tmp, sizeof(tmp), "%s..%s", path, + mg_random_str(rnd, sizeof(rnd))); + if (path_len < sizeof(tmp) && + (fd = mg_fs_open(fs, tmp, MG_FS_WRITE | MG_FS_EXCL)) != NULL) { result = fs->wr(fd->fd, buf, len) == len; mg_fs_close(fd); if (result) { fs->rm(path); - fs->mv(tmp, path); - } else { - fs->rm(tmp); + result = fs->mv(tmp, path); } + fs->rm(tmp); } return result; } diff --git a/src/fs.h b/src/fs.h index 51862dcb..326e86f3 100644 --- a/src/fs.h +++ b/src/fs.h @@ -4,7 +4,7 @@ #include "config.h" // Flags returned by mg_fs.st() and passed to mg_fs.open(). -enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4 }; +enum { MG_FS_READ = 1, MG_FS_WRITE = 2, MG_FS_DIR = 4, MG_FS_EXCL = 8 }; // Filesystem abstraction. Implement all function pointers to plug in a custom // filesystem. Short UNIX-style names are used deliberately to avoid conflicts diff --git a/src/fs_fat.c b/src/fs_fat.c index 3c5e7c06..33a6a64d 100644 --- a/src/fs_fat.c +++ b/src/fs_fat.c @@ -1,4 +1,5 @@ #include "arch.h" +#include "event.h" #include "fs.h" #if MG_ENABLE_FATFS @@ -69,17 +70,22 @@ static void ff_list(const char *dir, void (*fn)(const char *, void *), } static void *ff_open(const char *path, int flags) { - FIL f; + FIL *fp = NULL; unsigned char mode = FA_READ; - if (flags & MG_FS_WRITE) mode |= FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND; - if (f_open(&f, path, mode) == 0) { - FIL *fp; - if ((fp = mg_calloc(1, sizeof(*fp))) != NULL) { - memcpy(fp, &f, sizeof(*fp)); - return fp; + if (flags & MG_FS_WRITE) { + mode |= FA_WRITE; + if (flags & MG_FS_EXCL) { + mode |= FA_OPEN_ALWAYS | FA_OPEN_APPEND; + } else { + mode |= FA_CREATE_NEW; } } - return NULL; + if ((fp = mg_calloc(1, sizeof(*fp))) != NULL && + f_open(fp, path, mode) != FR_OK) { + mg_free(fp); + fp = NULL; + } + return fp; } static void ff_close(void *fp) { diff --git a/src/fs_posix.c b/src/fs_posix.c index 220119a9..064dc381 100644 --- a/src/fs_posix.c +++ b/src/fs_posix.c @@ -96,6 +96,7 @@ DIR *opendir(const char *name) { DIR *d = NULL; wchar_t wpath[MAX_PATH]; DWORD attrs; + size_t n; if (name == NULL) { SetLastError(ERROR_BAD_ARGUMENTS); @@ -105,9 +106,16 @@ DIR *opendir(const char *name) { to_wchar(name, wpath, sizeof(wpath) / sizeof(wpath[0])); attrs = GetFileAttributesW(wpath); if (attrs != 0Xffffffff && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { - (void) wcscat(wpath, L"\\*"); - d->handle = FindFirstFileW(wpath, &d->info); - d->result.d_name[0] = '\0'; + n = wcslen(wpath); + if (n <= (sizeof(wpath) / sizeof(wpath[0])) - 3) { + (void) wcscat(wpath, L"\\*"); + d->handle = FindFirstFileW(wpath, &d->info); + d->result.d_name[0] = '\0'; + } else { + mg_free(d); + d = NULL; + SetLastError(ERROR_BUFFER_OVERFLOW); + } } else { mg_free(d); d = NULL; @@ -169,13 +177,17 @@ static void p_list(const char *dir, void (*fn)(const char *, void *), static void *p_open(const char *path, int flags) { #if MG_ARCH == MG_ARCH_WIN32 - const char *mode = flags == MG_FS_READ ? "rb" : "a+b"; + const char *mode = flags == MG_FS_READ ? "rb" + : (flags & MG_FS_EXCL) ? "wxb" + : "a+b"; wchar_t b1[MG_PATH_MAX], b2[10]; MultiByteToWideChar(CP_UTF8, 0, path, -1, b1, sizeof(b1) / sizeof(b1[0])); MultiByteToWideChar(CP_UTF8, 0, mode, -1, b2, sizeof(b2) / sizeof(b2[0])); return (void *) _wfopen(b1, b2); #else - const char *mode = flags == MG_FS_READ ? "rbe" : "a+be"; // e for CLOEXEC + const char *mode = flags == MG_FS_READ ? "rbe" + : (flags & MG_FS_EXCL) ? "wxbe" + : "a+be"; // e for CLOSEXEC return (void *) fopen(path, mode); #endif } diff --git a/src/http.c b/src/http.c index 4ade7717..bfaea27a 100644 --- a/src/http.c +++ b/src/http.c @@ -65,14 +65,14 @@ size_t mg_http_next_multipart(struct mg_str body, size_t ofs, if (part != NULL) part->name = part->filename = part->body = mg_str_n(0, 0); // Skip boundary - while (b + 2 < max && s[b] != '\r' && s[b + 1] != '\n') b++; + while (b + 2 < max && !(s[b] == '\r' && s[b + 1] == '\n')) b++; if (b <= ofs || b + 2 >= max) return 0; // MG_INFO(("B: %zu %zu [%.*s]", ofs, b - ofs, (int) (b - ofs), s)); // Skip headers h1 = h2 = b + 2; for (;;) { - while (h2 + 2 < max && s[h2] != '\r' && s[h2 + 1] != '\n') h2++; + while (h2 + 2 < max && !(s[h2] == '\r' && s[h2 + 1] == '\n')) h2++; if (h2 == h1) break; if (h2 + 2 >= max) return 0; // MG_INFO(("Header: [%.*s]", (int) (h2 - h1), &s[h1])); @@ -320,7 +320,10 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) { if (!mg_http_parse_headers(s, end, hm->headers, sizeof(hm->headers) / sizeof(hm->headers[0]))) return -1; // error when parsing - if ((cl = mg_http_get_header(hm, "Content-Length")) != NULL) { + cl = mg_http_get_header(hm, "Content-Length"); + if (cl != NULL && mg_http_get_header(hm, "Transfer-Encoding") != NULL) + return -1; // cannot contain both CL and TE + if (cl != NULL) { if (mg_to_size_t(*cl, &hm->body.len) == false) return -1; hm->message.len = (size_t) req_len + hm->body.len; } @@ -676,6 +679,24 @@ struct printdirentrydata { }; #if MG_ENABLE_DIRLIST +// Print file name, escaping HTML chars +static size_t html_esc(void (*fn)(char, void *), void *arg, va_list *ap) { + const char *s = va_arg(*ap, const char *); + size_t i, len = 0; + for (i = 0; s[i] != '\0'; i++) { + if (s[i] == '<') { + len += mg_xprintf(fn, arg, "%s", "<"); + } else if (s[i] == '>') { + len += mg_xprintf(fn, arg, "%s", ">"); + } else if (s[i] == '&') { + len += mg_xprintf(fn, arg, "%s", "&"); + } else { + len += mg_xprintf(fn, arg, "%c", s[i]); + } + } + return len; +} + static void printdirentry(const char *name, void *userdata) { struct printdirentrydata *d = (struct printdirentrydata *) userdata; struct mg_fs *fs = d->opts->fs == NULL ? &mg_fs_posix : d->opts->fs; @@ -709,9 +730,9 @@ static void printdirentry(const char *name, void *userdata) { #endif n = (int) mg_url_encode(name, strlen(name), path, sizeof(path)); mg_printf(d->c, - " " + " " "\n", - n, path, slash, name, slash, (unsigned long) t, mod, + n, path, slash, html_esc, name, slash, (unsigned long) t, mod, flags & MG_FS_DIR ? (int64_t) -1 : (int64_t) size, sz); } } @@ -756,22 +777,21 @@ static void listdir(struct mg_connection *c, struct mg_http_message *hm, opts->extra_headers == NULL ? "" : opts->extra_headers); off = c->send.len; // Start of body mg_printf(c, - "Index of %.*s%s%s" + "Index of %M%s%s" "" - "

Index of %.*s

Name" "ModifiedSize

..[DIR]

%s%s
%M%s%s%s
" + "

Index of %M

" "" "" "" "" "\n", - (int) uri.len, uri.buf, sort_js_code, sort_js_code2, (int) uri.len, - uri.buf); + mg_print_html_esc, (int) uri.len, uri.buf, sort_js_code, sort_js_code2, + mg_print_html_esc, (int) uri.len, uri.buf); mg_printf(c, "%s", " " "\n"); - fs->ls(dir, printdirentry, &d); mg_printf(c, "" @@ -941,7 +961,8 @@ struct mg_str mg_http_get_header_var(struct mg_str s, struct mg_str v) { p++; // MG_INFO(("[%.*s] [%.*s] [%.*s]", (int) s.len, s.buf, (int) v.len, // v.buf, (int) (p - b), b)); - return stripquotes(mg_str_n(b, (size_t) (p - b + q))); + return stripquotes(mg_str_n(b, + (size_t) (p - b + (q && p < x && *p == '"' ? 1 : 0)))); } } return mg_str_n(NULL, 0); @@ -1098,7 +1119,7 @@ static int skip_chunk(const char *buf, int len, int *pl, int *dl) { while (i < len && is_hex_digit(buf[i])) i++; if (i == 0) return -1; // Error, no length specified if (i > (int) sizeof(int) * 2) return -1; // Chunk length is too big - if (len < i + 1 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error + if (len < i + 2 || buf[i] != '\r' || buf[i + 1] != '\n') return -1; // Error if (mg_str_to_num(mg_str_n(buf, (size_t) i), 16, &n, sizeof(int)) == false) return -1; // Decode chunk length, overflow if (n < 0) return -1; // Error. TODO(): some checks now redundant @@ -1142,7 +1163,7 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { hm.body.len = hm.message.len - (size_t) (hm.body.buf - hm.message.buf); } is_http_1_0 = - hm.proto.len > 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0; + hm.proto.len == 8 && mg_ncasecmp(hm.proto.buf, "HTTP/1.0", 8) == 0; // HTTP/1.0 does not use "Transfer-Encoding: chunked" if (!is_http_1_0 && (te = mg_http_get_header(&hm, "Transfer-Encoding")) != NULL) { diff --git a/src/l2_eth.c b/src/l2_eth.c index c7e3cfba..ee99a746 100644 --- a/src/l2_eth.c +++ b/src/l2_eth.c @@ -51,7 +51,7 @@ void mg_l2_eth_init(struct mg_tcpip_if *ifp) { MG_INFO( ("MAC not set. Generated random: %M", mg_print_mac, l2addr->addr.mac)); } - ifp->mtu = 1500; + ifp->l2mtu = 1500; ifp->framesize = 1540; } diff --git a/src/l2_ppp.c b/src/l2_ppp.c index 44903899..a7ecf160 100644 --- a/src/l2_ppp.c +++ b/src/l2_ppp.c @@ -100,7 +100,7 @@ static uint8_t s_state = MG_PPPoE_ST_DISC; static uint16_t s_id; void mg_l2_ppp_init(struct mg_tcpip_if *ifp) { - ifp->mtu = 1500; + ifp->l2mtu = 1500; ifp->framesize = 1500 + sizeof(struct ppp) + sizeof(struct hdlc_); } @@ -108,7 +108,7 @@ extern void mg_l2_eth_init(struct mg_tcpip_if *); void mg_l2_pppoe_init(struct mg_tcpip_if *ifp) { mg_l2_eth_init(ifp); - ifp->mtu = ifp->mtu - (uint16_t) (sizeof(struct pppoe) + + ifp->l2mtu = ifp->l2mtu - (uint16_t) (sizeof(struct pppoe) + sizeof(struct ppp)); // 1500 --> 1492 } @@ -277,8 +277,8 @@ static void ppp_handle_lcp(struct mg_tcpip_if *ifp, uint8_t *lcpp, static bool find_opt(const uint8_t opt, const uint8_t optlen, const uint8_t *opts, size_t optslen, uint8_t *dest) { uint8_t *p = (uint8_t *) opts; - while (optslen >= 2) { // parse options for requested one - if (p[1] > optslen) return false; // truncated / malformed + while (optslen >= 2) { // parse options for requested one + if (p[1] > optslen || p[1] < 2) return false; // truncated / malformed if (p[0] == opt && p[1] == optlen) { memcpy(dest, p + 2, optlen - 2); return true; @@ -299,6 +299,7 @@ static void ppp_handle_ipcp(struct mg_tcpip_if *ifp, uint8_t *ipcpp, if (ipcpsz < sizeof(*ipcp)) return; id = ipcp->id; len = mg_ntohs(ipcp->len); + if (len > ipcpsz) return; switch (ipcp->code) { case MG_PPP_IPCP_CFG_REQ: MG_VERBOSE(("got IPCP config request, acknowledging...")); @@ -449,8 +450,9 @@ static bool ppp_rx(struct mg_tcpip_if *ifp, enum mg_l2proto *proto, size_t msglen; MG_DEBUG(("unknown %u-byte PPP frame with proto 0x%04x:", pay->len + sizeof(*ppp), mg_ntohs(ppp->proto))); - if (mg_log_level >= MG_LL_DEBUG) mg_hexdump(ppp, sizeof(*ppp) + 20); - if (!s_lcpup) return false; // RFC-1661 5.7: must reject on link up + if (mg_log_level >= MG_LL_DEBUG) + mg_hexdump(ppp, pay->len > 14 ? 16 : pay->len + sizeof(*ppp)); + if (!s_lcpup) return false; // RFC-1661 5.7: must reject on link down if (pay->len > (size_t) (ifp->mtu - 20)) pay->len = (size_t) (ifp->mtu - 20); // truncate to some safe limit rej.code = MG_PPP_LCP_REJECT; diff --git a/src/mqtt.c b/src/mqtt.c index 57f5fae7..54ae5f40 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -198,12 +198,15 @@ static bool mg_send_mqtt_properties(struct mg_connection *c, size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, size_t ofs) { - uint8_t *i = (uint8_t *) msg->dgram.buf + msg->props_start + ofs; - uint8_t *end = (uint8_t *) msg->dgram.buf + msg->dgram.len; + uint8_t *props = (uint8_t *) msg->dgram.buf + msg->props_start; + uint8_t *props_end = props + msg->props_size; + uint8_t *i = props + ofs; size_t new_pos = ofs, len; - - if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size || (i + 1) >= end) - return 0; + + if (msg->props_start > msg->dgram.len || + msg->props_size > msg->dgram.len - msg->props_start || + ofs >= msg->props_size) + return 0; memset(prop, 0, sizeof(struct mg_mqtt_prop)); prop->id = i[0]; @@ -211,49 +214,50 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, switch (mqtt_prop_type_by_id(prop->id)) { case MQTT_PROP_TYPE_STRING_PAIR: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); + if (i + 2 + prop->key.len > props_end) return 0; prop->key.buf = (char *) i + 2; i += 2 + prop->key.len; - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; - if (i + 2 + prop->val.len >= end) return 0; + if (i + 2 + prop->val.len > props_end) return 0; new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; break; case MQTT_PROP_TYPE_BYTE: - if (i + 1 >= end) return 0; + if (i + 1 > props_end) return 0; prop->iv = (uint8_t) i[0]; new_pos++; break; case MQTT_PROP_TYPE_SHORT: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); new_pos += sizeof(uint16_t); break; case MQTT_PROP_TYPE_INT: - if (i + 4 >= end) return 0; + if (i + 4 > props_end) return 0; prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | ((uint32_t) i[2] << 8) | i[3]; new_pos += sizeof(uint32_t); break; case MQTT_PROP_TYPE_STRING: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; - if (i + 2 + prop->val.len >= end) return 0; + if (i + 2 + prop->val.len > props_end) return 0; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_BINARY_DATA: - if (i + 2 >= end) return 0; + if (i + 2 > props_end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; - if (i + 2 + prop->val.len >= end) return 0; + if (i + 2 + prop->val.len > props_end) return 0; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_VARIABLE_INT: - len = decode_varint(i, (size_t) (end - i), &prop->iv); - if (i + len >= end) return 0; + len = decode_varint(i, (size_t) (props_end - i), &prop->iv); + if (i + len > props_end) return 0; new_pos = (len == 0) ? 0 : new_pos + len; break; default: diff --git a/src/net_builtin.c b/src/net_builtin.c index ab14ebcf..c95a3d0a 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -630,7 +630,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { size_t plen = pkt->pay.len; if (!icmpcsum_ok(pkt->icmp, sizeof(struct icmp) + plen)) return; if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { - size_t l2_max_overhead = ifp->framesize - ifp->mtu; + size_t l2_max_overhead = ifp->framesize - ifp->l2mtu; size_t hlen = sizeof(struct ip) + sizeof(struct icmp); size_t room = ifp->tx.len - hlen - l2_max_overhead; uint8_t *l2addr; @@ -662,9 +662,9 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0, owner = 0; uint8_t msgtype = 0, state = ifp->state; // perform size check first, then access fields - uint8_t *p = pkt->dhcp->options, + uint8_t *p = (uint8_t *) pkt->pay.buf, *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len]; - if (end < p) return; // options are optional, check min header length + // min header length checked at payload calculation, options are optional if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; while (p + 1 < end && p[0] != 255) { // Parse options, get #1; RFC-2132 9 if (p[0] == 1 && p[1] == 4 && p + 6 < end) { // Mask, 3.3 @@ -704,7 +704,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (msgtype == 5) { // DHCPACK if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP uint64_t rand; - ifp->lease_expire = ifp->now + lease * 1000; + ifp->lease_expire = ifp->now + (uint64_t) lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, mg_l2_getaddr(ifp, pkt->l2), sizeof(ifp->gwmac)); @@ -721,7 +721,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (ifp->enable_req_sntp && sntp != 0) mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew - ifp->lease_expire = ifp->now + lease * 1000; + ifp->lease_expire = ifp->now + (uint64_t) lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); } // TODO(): accept provided T1/T2 and store server IP for renewal (4.4) } @@ -731,11 +731,11 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // Simple DHCP server that assigns a next IP address: ifp->ip + 1 static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint8_t *mac; - uint8_t op = 0, *p = pkt->dhcp->options, + uint8_t op = 0, *p = (uint8_t *) pkt->pay.buf, *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len]; // NOTE(): assumes Ethernet: htype=1 hlen=6, copy 6 bytes struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}}; - if (end < p) return; // options are optional, check min header length + // min header length checked at payload calculation, options are optional res.yiaddr = ifp->ip; ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 while (p + 1 < end && p[0] != 255) { // Parse options @@ -827,14 +827,16 @@ static void tx_ndp_na(struct mg_tcpip_if *ifp, uint8_t *l2_dst, static void onstate6change(struct mg_tcpip_if *ifp); static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) { - struct ndp_na *na = (struct ndp_na *) (pkt->icmp6 + 1); - uint8_t *opts = (uint8_t *) (na + 1); + struct ndp_na *na = (struct ndp_na *) pkt->pay.buf; + uint8_t *opts = (uint8_t *) (na + 1), *endp = opts + pkt->pay.len - sizeof(*na); + if (pkt->pay.len < (sizeof(*na) + 2)) return; // first 2 bytes in opts if ((na->res[0] & 0x40) == 0) return; // not "solicited" - if (*opts++ != 2) return; // no target hwaddr + if (*opts++ != 2) return; // no target hwaddr, must have MG_VERBOSE(("NDP NA resp from %M", mg_print_ip6, (char *) &na->addr)); if (MG_IP6MATCH(na->addr, ifp->gw6)) { // Got response for the GW NS request. Set ifp->gw6mac and IP6 -> READY uint8_t len = *opts++; // check valid hwaddr and get it + if ((opts + 8 * len - 2) > endp) return; // truncated if (!mg_l2_ip6get(ifp->l2type, ifp->gw6mac, opts, len)) return; ifp->gw6_ready = true; if (ifp->state6 == MG_TCPIP_STATE_IP) { @@ -846,6 +848,7 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (c != NULL && c->is_arplooking) { struct connstate *s = (struct connstate *) (c + 1); uint8_t len = *opts++; // check valid hwaddr and get it + if ((opts + 8 * len - 2) > endp) return; // truncated if (!mg_l2_ip6get(ifp->l2type, s->mac, opts, len)) return; MG_DEBUG(("%lu NDP resolved %M -> %M", c->id, mg_print_ip6, &c->rem.addr.ip6, mg_print_l2addr, ifp->l2type, s->mac)); @@ -857,15 +860,17 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) { // Neighbor Solicitation, 4.3 static void rx_ndp_ns(struct mg_tcpip_if *ifp, struct pkt *pkt) { + struct ndp_na *ns = (struct ndp_na *) pkt->pay.buf; // struct ndp_ns = ndp_na uint64_t target[2]; - if (pkt->pay.len < sizeof(target)) return; - memcpy(target, pkt->pay.buf + 4, sizeof(target)); + if (pkt->pay.len < (sizeof(*ns) + 2)) return; // first 2 bytes in opts + memcpy(target, ns->addr, sizeof(target)); if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) { uint64_t req[2]; // requester address uint8_t l2[sizeof(struct mg_l2addr)]; - uint8_t len, *opts = (uint8_t *) pkt->pay.buf + 20; + uint8_t len, *opts = (uint8_t *) (ns + 1), *endp = opts + pkt->pay.len - sizeof(*ns); if (*opts++ != 1) return; // no requester hwaddr (source) len = *opts++; // check valid hwaddr and get it + if ((opts + 8 * len - 2) > endp) return; // truncated if (!mg_l2_ip6get(ifp->l2type, l2, opts, len)) return; req[0] = pkt->ip6->src[0], req[1] = pkt->ip6->src[1]; // align to 64-bit tx_ndp_na(ifp, l2, target, req, true, ifp->mac); @@ -961,15 +966,15 @@ static bool fill_global(struct mg_tcpip_if *ifp, uint8_t *prefix, // Router Advertisement, 4.2 static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { - if (pkt->pay.len < 12) return; - struct ndp_ra *ra = (struct ndp_ra *) (pkt->icmp6 + 1); + struct ndp_ra *ra = (struct ndp_ra *) pkt->pay.buf; uint8_t *opts = (uint8_t *) (ra + 1); - size_t opt_left = pkt->pay.len - 12; + size_t opt_left = pkt->pay.len - sizeof(*ra); bool gotl2addr = false, gotprefix = false, changed = false; uint8_t l2[sizeof(struct mg_l2addr)]; uint32_t mtu = 0; uint8_t *prefix, prefix_len; + if (pkt->pay.len < sizeof(*ra)) return; if (ifp->state6 == MG_TCPIP_STATE_UP) { MG_DEBUG(("Received NDP RA")); // fill gw6 address // parse options @@ -982,8 +987,9 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (!mg_l2_ip6get(ifp->l2type, l2, opts + 2, len)) break; gotl2addr = true; } else if (type == 5 && length >= 8) { - // process MTU if available + // process MTU if available, ignore if it smells mtu = MG_LOAD_BE32(opts + 4); + if (mtu < 1280 || mtu > ifp->l2mtu) mtu = 0; // RFC-8200, minimum MTU } else if (type == 3 && length >= 32) { // process prefix, 4.6.2 uint8_t pfx_flags = opts[3]; // L=0x80, A=0x40 @@ -1037,7 +1043,7 @@ static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint64_t target[2]; target[0] = pkt->ip6->dst[0], target[1] = pkt->ip6->dst[1]; if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) { - size_t l2_max_overhead = ifp->framesize - ifp->mtu; + size_t l2_max_overhead = ifp->framesize - ifp->l2mtu; size_t hlen = sizeof(struct ip6) + sizeof(struct icmp6); size_t room = ifp->tx.len - hlen - l2_max_overhead, plen = pkt->pay.len; struct mg_addr ips; @@ -1328,7 +1334,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn, static size_t trim_len(struct mg_connection *c, size_t len) { struct mg_tcpip_if *ifp = c->mgr->ifp; - size_t l2_max_overhead = ifp->framesize - ifp->mtu; + size_t l2_max_overhead = ifp->framesize - ifp->l2mtu; size_t ip_max_h_len = c->rem.is_ip6 ? 40 : 24; // we don't send options size_t tcp_max_h_len = 60 /* RFC-9293 3.7.1; RFC-6691 2 */, udp_h_len = 8; size_t max_headers_len = @@ -1715,11 +1721,13 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->udp->dport), (int) pkt->pay.len)); - if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68)) { + if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(68) && + len >= offsetof(struct dhcp, options)) { pkt->dhcp = (struct dhcp *) (pkt->udp + 1); mkpay(pkt, &pkt->dhcp->options); rx_dhcp_client(ifp, pkt); - } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67)) { + } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(67) && + len >= offsetof(struct dhcp, options)) { pkt->dhcp = (struct dhcp *) (pkt->udp + 1); mkpay(pkt, &pkt->dhcp->options); rx_dhcp_server(ifp, pkt); @@ -1757,19 +1765,24 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { next = pkt->ip6->next; nhdr = (uint8_t *) (pkt->ip6 + 1); while (loop) { + uint16_t hlen; switch (next) { case 0: // Hop-by-Hop 4.3 case 43: // Routing 4.4 case 60: // Destination Options 4.6 case 51: // Authentication RFC-4302 MG_INFO(("IPv6 extension header %d", (int) next)); + if (((uint32_t) len + 2) > plen) return; // nhdr[0, 1]; malformed next = nhdr[0]; - len += (uint16_t) (8 * (nhdr[1] + 1)); - nhdr += 8 * (nhdr[1] + 1); + hlen = (uint16_t) (8 * (nhdr[1] + 1)); + if (((uint32_t) len + hlen) > plen) return; // malformed + len += hlen; + nhdr += hlen; break; case 44: // Fragment 4.5 { struct mg_connection *c; + if (((uint32_t) len + 2) > plen) return; // nhdr[0, 1]; malformed if (nhdr[0] == 17) pkt->udp = (struct udp *) (pkt->pay.buf); if (nhdr[0] == 6) pkt->tcp = (struct tcp *) (pkt->pay.buf); c = getpeer(ifp->mgr, pkt, false); @@ -1784,7 +1797,6 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) { break; } } - if (len >= plen) return; // There can be link padding, take payload length from IPv6 header - options pkt->pay.buf = (char *) nhdr; pkt->pay.len = plen - len; @@ -2062,6 +2074,7 @@ void mg_tcpip_qwrite(void *buf, size_t len, struct mg_tcpip_if *ifp) { void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) { // If L2 address is not set, make a random one; fill MTU mg_l2_init(ifp); + ifp->mtu = ifp->l2mtu; if (ifp->dhcp_name[0] == '\0') // If DHCP name is not set, use "mip" memcpy(ifp->dhcp_name, "mip", 4); diff --git a/src/net_builtin.h b/src/net_builtin.h index 170e839e..bb41216c 100644 --- a/src/net_builtin.h +++ b/src/net_builtin.h @@ -70,6 +70,7 @@ struct mg_tcpip_if { char dhcp_name[MG_TCPIP_DHCPNAME_SIZE]; // Hostname sent in DHCP requests; defaults to "mip" uint16_t mtu; // IP MTU (max payload size at the IP layer) uint16_t framesize; // Maximum L2 frame size in bytes + uint16_t l2mtu; // L2 frame payload, default net MTU #if MG_ENABLE_IPV6 uint64_t ip6ll[2], ip6[2]; // IPv6 link-local and global addresses diff --git a/src/printf.c b/src/printf.c index c6202c7d..409bcb6b 100644 --- a/src/printf.c +++ b/src/printf.c @@ -209,3 +209,31 @@ size_t mg_print_esc(void (*out)(char, void *), void *arg, va_list *ap) { if (len == 0) len = p == NULL ? 0 : strlen(p); return qcpy(out, arg, p, len); } + +size_t mg_print_html_esc(void (*out)(char, void *), void *arg, va_list *ap) { + size_t i, n = 0; + int len = va_arg(*ap, int); + const char *s = va_arg(*ap, const char *); + for (i = 0; i < (size_t) len; i++) { + const char *esc = NULL; + switch (s[i]) { + // clang-format off + case '&': esc = "&"; break; + case '<': esc = "<"; break; + case '>': esc = ">"; break; + case '"': esc = """; break; + default: break; + // clang-format on + } + if (esc != NULL) { + while (*esc != '\0') { + out(*esc++, arg); + n++; + } + } else { + out(s[i], arg); + n++; + } + } + return n; +} diff --git a/src/printf.h b/src/printf.h index aa381d48..b6dade93 100644 --- a/src/printf.h +++ b/src/printf.h @@ -35,7 +35,7 @@ size_t mg_queue_printf(struct mg_queue *, const char *fmt, ...); // Built-in %M/%m printer functions. Each reads its argument(s) from ap. size_t mg_print_base64(mg_pfn_t, void *arg, va_list *ap); // expects: const void *buf, size_t len -size_t mg_print_esc(mg_pfn_t, void *arg, va_list *ap); // expects: int quote, const char *str -- use MG_ESC() +size_t mg_print_esc(mg_pfn_t, void *arg, va_list *ap); // expects: int len, const char *str -- use MG_ESC() size_t mg_print_hex(mg_pfn_t, void *arg, va_list *ap); // expects: const void *buf, size_t len size_t mg_print_ip(mg_pfn_t, void *arg, va_list *ap); // expects: const struct mg_addr * size_t mg_print_ip_port(mg_pfn_t, void *arg, va_list *ap); // expects: const struct mg_addr * @@ -44,6 +44,8 @@ size_t mg_print_ip6(mg_pfn_t, void *arg, va_list *ap); // expects: uint8_t[ size_t mg_print_mac(mg_pfn_t, void *arg, va_list *ap); // expects: uint8_t[6] mac size_t mg_print_ieee64(mg_pfn_t, void *arg, va_list *ap); // expects: uint64_t size_t mg_print_l2addr(mg_pfn_t, void *arg, va_list *ap); // expects: uint8_t l2, uint8_t[n] n-byte l2-dependent address +size_t mg_print_html_esc(mg_pfn_t, void *arg, va_list *ap); // expects: int len, const char *str -- use MG_ESC() + // Output functions for use as the fn argument to mg_xprintf/mg_vxprintf. void mg_pfn_iobuf(char ch, void *param); // param: struct mg_iobuf * (resizes as needed) diff --git a/src/sock.c b/src/sock.c index 428734f0..56c4dc7d 100644 --- a/src/sock.c +++ b/src/sock.c @@ -112,9 +112,9 @@ void mg_getlocaddr(struct mg_connection *c, struct mg_addr *to, slen = tousa(to, &usa); if ((rc = connect(fd, &usa.sa, slen)) != 0) { mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); - return; + } else { + setlocaddr(fd, addr); } - setlocaddr(fd, addr); closesocket(fd); } diff --git a/src/ssi.c b/src/ssi.c index 8947e423..1c4a5f16 100644 --- a/src/ssi.c +++ b/src/ssi.c @@ -21,7 +21,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { size_t len = 0; buf[0] = arg[0] = '\0'; while ((ch = fgetc(fp)) != EOF) { - if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { + if (intag && ch == '>' && len >= 2 && buf[len - 1] == '-' && buf[len - 2] == '-') { buf[len++] = (char) (ch & 0xff); buf[len] = '\0'; if (sscanf(buf, " [%.*s]", (int) part.body.len, part.body.buf)); @@ -3487,9 +3537,13 @@ static void test_rewrites(void) { static void test_get_header_var(void) { struct mg_str empty = mg_str(""), bar = mg_str("bar"), baz = mg_str("baz"); struct mg_str header = mg_str("Digest foo=\"bar\", blah,boo=baz, x=\"yy\""); + struct mg_str bad_header = mg_str("Digest foo=\"bar"); struct mg_str yy = mg_str("yy"); // struct mg_str x = mg_http_get_header_var(header, mg_str("x")); // MG_INFO(("--> [%d] [%d]", (int) x.len, yy.len)); + struct mg_str bad_value = mg_http_get_header_var(bad_header, mg_str("foo")); + ASSERT(bad_value.len == 4); + ASSERT(mg_strcmp(mg_str("\"bar"), bad_value) == 0); ASSERT(mg_strcmp(empty, mg_http_get_header_var(empty, empty)) == 0); ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, empty)) == 0); ASSERT(mg_strcmp(empty, mg_http_get_header_var(header, mg_str("fooo"))) == 0); @@ -4134,57 +4188,116 @@ static void test_x25519(void) { static void test_rsa(void) { #if MG_TLS == MG_TLS_BUILTIN - const unsigned char mod[] = { - 0x00, 0xba, 0xee, 0x3b, 0x0b, 0x89, 0x58, 0xa6, 0x19, 0x0d, 0x4c, 0x89, - 0x1a, 0x85, 0x9a, 0xf4, 0x55, 0xc2, 0xdd, 0x0d, 0xd4, 0x4a, 0xf5, 0xed, - 0xda, 0x28, 0x55, 0x2f, 0x64, 0x46, 0x21, 0x9f, 0x46, 0x5c, 0xfa, 0x37, - 0x88, 0x11, 0xdf, 0xcb, 0x51, 0x73, 0x42, 0x3d, 0x5e, 0x50, 0xde, 0x11, - 0x30, 0x61, 0x04, 0x59, 0xd0, 0xf4, 0x57, 0xed, 0x13, 0x90, 0x32, 0xc5, - 0x3f, 0xe6, 0x66, 0xfc, 0x2a, 0x12, 0xa3, 0x1f, 0xd1, 0x77, 0x21, 0x65, - 0xdf, 0x9a, 0xcf, 0x04, 0x05, 0xc3, 0x1c, 0xf8, 0x79, 0xb5, 0xf5, 0x97, - 0x68, 0x98, 0x2e, 0x96, 0x85, 0x3f, 0xee, 0x71, 0x91, 0xc1, 0x54, 0x71, - 0x9a, 0x80, 0x1f, 0xbe, 0x21, 0xd9, 0xc1, 0x80, 0x9b, 0xd0, 0x5d, 0xb3, - 0x76, 0x3e, 0xcc, 0x14, 0x3d, 0xec, 0xb7, 0x18, 0x74, 0xfb, 0xc4, 0x0e, - 0x56, 0x8d, 0x3d, 0x78, 0xe6, 0xca, 0xcd, 0x9d, 0xc6, 0x20, 0x5a, 0xeb, - 0x9b, 0xc8, 0x19, 0x5e, 0xeb, 0x80, 0xd2, 0xb2, 0xfe, 0x88, 0x15, 0x5c, - 0x7c, 0x6b, 0x26, 0xe0, 0x43, 0xda, 0xa4, 0x07, 0x85, 0x73, 0xc4, 0x80, - 0x28, 0xcb, 0xda, 0x18, 0x56, 0x37, 0x91, 0xd6, 0x41, 0xa1, 0x0b, 0xa2, - 0x77, 0xd0, 0x62, 0x31, 0xc7, 0xc2, 0x67, 0x6d, 0x75, 0x08, 0x80, 0xe7, - 0xb6, 0xbe, 0xc2, 0x25, 0xc9, 0xe0, 0x2c, 0x02, 0xbf, 0x39, 0x61, 0x7e, - 0x32, 0xa4, 0xc9, 0xe7, 0x91, 0xe3, 0xa0, 0xcd, 0x94, 0x24, 0xbf, 0x8c, - 0xeb, 0x47, 0x76, 0x53, 0x85, 0xb3, 0xb7, 0x31, 0x80, 0x3c, 0x77, 0x10, - 0x69, 0xc3, 0x04, 0xd1, 0x60, 0x4c, 0x74, 0xda, 0x15, 0x18, 0x0b, 0x20, - 0x6f, 0xb3, 0x03, 0x58, 0x4a, 0xfc, 0xd1, 0xd2, 0xcf, 0x37, 0x15, 0x0a, - 0x63, 0xc8, 0xe9, 0xd5, 0x7d, 0xd5, 0xf2, 0x90, 0x78, 0x53, 0x49, 0xa9, - 0xc5, 0x25, 0x65, 0x5c, 0x01}; - const unsigned char exp[] = {1, 0, 1}; // 65537 - const unsigned char sig[] = { - 0x1e, 0xb1, 0x6a, 0xcb, 0x39, 0x63, 0x12, 0xed, 0x85, 0x62, 0x4b, 0x85, - 0x47, 0x25, 0x67, 0xbd, 0xbd, 0x0e, 0xaa, 0x73, 0x34, 0x5f, 0x07, 0x2b, - 0xbb, 0x4f, 0xf5, 0x21, 0x88, 0xb1, 0x04, 0x2c, 0xbb, 0x52, 0x72, 0x64, - 0x89, 0x45, 0x50, 0x41, 0x73, 0xca, 0xda, 0x97, 0xae, 0x81, 0x89, 0x4f, - 0x83, 0x8d, 0x48, 0x65, 0x63, 0xe7, 0x82, 0x03, 0xd2, 0x40, 0x07, 0x1c, - 0x86, 0x58, 0xd5, 0xac, 0x89, 0xb1, 0xca, 0x5c, 0xde, 0x21, 0x06, 0x88, - 0x88, 0x0c, 0xe1, 0x20, 0xc0, 0xdf, 0xf1, 0x92, 0x9b, 0xb8, 0xa5, 0xeb, - 0x6d, 0x89, 0xcc, 0x5c, 0x5c, 0x24, 0x3e, 0x9b, 0x3c, 0x35, 0x32, 0xa5, - 0x04, 0x9e, 0x8c, 0x49, 0x01, 0xee, 0xbf, 0x1f, 0x2c, 0xb0, 0x52, 0xa8, - 0xab, 0x79, 0x11, 0xcf, 0xb5, 0x5a, 0x16, 0xa1, 0xee, 0x21, 0x6a, 0x5a, - 0x2b, 0x14, 0xae, 0x32, 0x3c, 0xa2, 0x6c, 0xa2, 0x40, 0x0c, 0xcb, 0x9e, - 0x8f, 0x69, 0xab, 0xd7, 0xf3, 0xd8, 0xd1, 0xfb, 0x2d, 0xfa, 0xa9, 0x13, - 0x09, 0xbf, 0xa7, 0xca, 0xc8, 0x90, 0x74, 0x23, 0x7b, 0x3e, 0xdd, 0x81, - 0x32, 0xa7, 0x88, 0x42, 0x56, 0x8a, 0xcb, 0xe8, 0x8f, 0xef, 0x06, 0x9f, - 0x39, 0x7e, 0x8e, 0x24, 0x07, 0xb3, 0xae, 0x7e, 0x13, 0x6b, 0xf2, 0xf8, - 0x35, 0xe4, 0x16, 0x3e, 0xae, 0xf2, 0x55, 0x79, 0x10, 0x39, 0xfa, 0x70, - 0x3a, 0x1b, 0x02, 0xb3, 0x2b, 0x1d, 0x44, 0xac, 0x30, 0x81, 0xd3, 0x11, - 0xdd, 0x34, 0x1e, 0xcd, 0x26, 0xf5, 0x89, 0xc6, 0x55, 0x23, 0x17, 0x09, - 0xd2, 0xc1, 0xdc, 0x49, 0xf9, 0x99, 0x36, 0x2b, 0xf5, 0xae, 0x42, 0x5c, - 0xb7, 0x80, 0xda, 0x32, 0x69, 0x28, 0xa3, 0xee, 0xb9, 0xd4, 0x90, 0xa6, - 0xab, 0x34, 0x17, 0x5e, 0xa0, 0xd6, 0xc1, 0x54, 0xc6, 0x9c, 0x58, 0x3a, - 0xaf, 0xbf, 0xdc, 0x64}; - unsigned char v[256]; // 2048 bits - mg_rsa_mod_pow(mod, sizeof(mod), exp, sizeof(exp), sig, sizeof(sig), v, - sizeof(v)); - ASSERT(v[sizeof(v) - 1] == 0xbc); + static const uint8_t tv_n[256] = { + 0xe5, 0xd5, 0x5c, 0xed, 0xa7, 0xeb, 0xdd, 0x7f, 0x2a, 0x23, 0xd3, 0x2b, + 0xd1, 0x01, 0x4e, 0xd3, 0x06, 0x51, 0x8a, 0x7f, 0x49, 0xaa, 0x1d, 0xa0, + 0x6b, 0xa4, 0x75, 0x2d, 0x88, 0x99, 0x12, 0x20, 0x56, 0x43, 0x4a, 0x32, + 0x52, 0xa4, 0x92, 0x4f, 0x9e, 0xae, 0x73, 0x7e, 0x22, 0x78, 0x8e, 0xec, + 0x64, 0x0a, 0xff, 0xeb, 0x02, 0x9e, 0xfe, 0x0c, 0xbf, 0x37, 0x4e, 0xf9, + 0xb3, 0x71, 0x23, 0x29, 0xae, 0x22, 0xc9, 0x9e, 0xa3, 0xc9, 0x63, 0xa8, + 0x89, 0x39, 0x89, 0xf0, 0x37, 0x27, 0x1a, 0xbf, 0x9b, 0x70, 0x35, 0xf2, + 0x7c, 0x0f, 0x34, 0xf2, 0x80, 0x6b, 0x9b, 0x80, 0x98, 0x16, 0x64, 0xba, + 0x7e, 0x51, 0x22, 0xe1, 0xca, 0x39, 0x8c, 0x6c, 0x0b, 0xc6, 0x6b, 0xc8, + 0x74, 0x50, 0x84, 0x9b, 0xe3, 0xf1, 0xdb, 0xf5, 0xff, 0x7e, 0x49, 0xe8, + 0xdc, 0x41, 0xb9, 0x25, 0x3e, 0x2d, 0xbc, 0x48, 0x8f, 0xc8, 0x6f, 0x1b, + 0x6b, 0x8a, 0xeb, 0xdb, 0x68, 0xaa, 0x15, 0xd9, 0x5e, 0xd8, 0x11, 0x07, + 0x03, 0xbd, 0xd2, 0xa9, 0x6f, 0xce, 0x58, 0xb1, 0xb1, 0x86, 0xff, 0x86, + 0x6e, 0x4a, 0x81, 0x64, 0xa0, 0x6c, 0x83, 0xca, 0xfc, 0x3f, 0xfe, 0x7d, + 0x95, 0xd6, 0x40, 0x29, 0x21, 0x5a, 0x3b, 0x5d, 0xc8, 0x93, 0xa0, 0x1d, + 0x2c, 0x6e, 0xb6, 0xc0, 0x65, 0x15, 0x69, 0x8b, 0x67, 0x71, 0x03, 0xde, + 0xe7, 0xcc, 0x65, 0x83, 0x0e, 0x5a, 0x9d, 0xc9, 0x0e, 0xc1, 0xc7, 0xc4, + 0xf3, 0x47, 0x1e, 0x9d, 0xce, 0x9d, 0xaf, 0x8b, 0x5f, 0xaa, 0x35, 0xfe, + 0x15, 0x59, 0xd4, 0xc1, 0xd5, 0xaa, 0x3b, 0x3a, 0x0d, 0x9a, 0x98, 0x88, + 0x1b, 0x5e, 0xf8, 0x5b, 0x07, 0xbf, 0xdb, 0x5e, 0x88, 0x46, 0x4a, 0xde, + 0x9a, 0x63, 0x30, 0x7b, 0x4f, 0x3f, 0xc6, 0x9b, 0x88, 0x98, 0x34, 0xbe, + 0xfd, 0xbb, 0xf5, 0xd1}; + + static const uint8_t tv_e[3] = {0x01, 0x00, 0x01}; + + static const uint8_t tv_sig[256] = { + 0x8f, 0xc5, 0x67, 0x8f, 0x44, 0xae, 0x2c, 0x03, 0x2b, 0xb4, 0xfb, 0xd5, + 0x1a, 0xba, 0xc7, 0xd2, 0x7a, 0x9a, 0xaa, 0x2d, 0x31, 0x49, 0x4c, 0x73, + 0x46, 0x38, 0x1e, 0xd6, 0xb2, 0xc0, 0x8f, 0x2f, 0x8c, 0xf6, 0xba, 0x7c, + 0x81, 0xe4, 0xbe, 0x37, 0x09, 0xb3, 0x9a, 0xae, 0x7e, 0x06, 0xcd, 0x3a, + 0x48, 0xc3, 0x6a, 0x7b, 0x06, 0x28, 0x70, 0x06, 0x4c, 0xd9, 0x38, 0xa8, + 0x25, 0x7e, 0x6f, 0xdc, 0x65, 0xc0, 0x17, 0x2c, 0x7b, 0x97, 0x1e, 0x61, + 0x00, 0xb9, 0xdf, 0xd0, 0x2b, 0x54, 0x3a, 0xff, 0x18, 0x32, 0x8e, 0x69, + 0x5e, 0x64, 0x47, 0x68, 0xd8, 0x3a, 0x78, 0xf0, 0x91, 0x7d, 0x6b, 0xe0, + 0xc1, 0x6b, 0x5f, 0xd8, 0x7b, 0x22, 0xd6, 0x5d, 0x3b, 0x73, 0xf2, 0x1c, + 0x9c, 0x73, 0xb7, 0x29, 0x22, 0xaf, 0x27, 0x0c, 0xce, 0x29, 0xa1, 0x46, + 0x09, 0x5f, 0x9a, 0x9f, 0xa5, 0x6f, 0x88, 0x65, 0x23, 0x68, 0xaf, 0x1d, + 0x56, 0x32, 0x69, 0x6f, 0x9c, 0x2d, 0x93, 0x0d, 0x99, 0x8a, 0x39, 0x53, + 0x82, 0x0a, 0xae, 0xe2, 0xe3, 0xf1, 0x03, 0x7a, 0xb3, 0x5b, 0x05, 0x6d, + 0xdd, 0xbe, 0xb5, 0x0d, 0x53, 0x81, 0x93, 0x9b, 0xdb, 0xd6, 0x39, 0x61, + 0x97, 0x0c, 0x23, 0xd3, 0x98, 0x51, 0xb1, 0xd9, 0x42, 0x1d, 0x5d, 0x29, + 0x2b, 0x64, 0xda, 0xa9, 0x37, 0x70, 0x30, 0x77, 0xa0, 0x99, 0x8d, 0x13, + 0x67, 0x5d, 0x68, 0x80, 0x9f, 0x68, 0x25, 0x30, 0x50, 0x31, 0xe3, 0xed, + 0xd2, 0xa2, 0xa0, 0xfc, 0xf7, 0xb4, 0x85, 0xbf, 0x68, 0xdc, 0x14, 0xbc, + 0xeb, 0xd7, 0x9f, 0x7a, 0x6a, 0xb1, 0x9c, 0x8b, 0xf5, 0xff, 0xc1, 0x5a, + 0xf7, 0xaf, 0x52, 0x88, 0x0e, 0xf2, 0x5c, 0x10, 0x02, 0x35, 0xe2, 0xcc, + 0xd9, 0x2b, 0x20, 0x80, 0xc2, 0xb9, 0xfa, 0x5f, 0xbd, 0xc6, 0xd2, 0xd7, + 0xc1, 0xe3, 0xcd, 0x59}; + + static const uint8_t tv_em[256] = { + 0x17, 0x08, 0xf4, 0xe4, 0x67, 0x2b, 0xa9, 0x3b, 0x34, 0x13, 0x96, 0xeb, + 0xd1, 0x14, 0xf1, 0x90, 0x4c, 0x6f, 0xc9, 0xec, 0xa0, 0x85, 0xa8, 0xa6, + 0x89, 0xe4, 0xd4, 0x48, 0x41, 0x5b, 0x6b, 0x1c, 0x79, 0xce, 0x87, 0xdb, + 0x12, 0x45, 0x97, 0x3b, 0x37, 0xd9, 0xd6, 0xe9, 0x7e, 0x6e, 0xcf, 0xb2, + 0x84, 0x47, 0xe4, 0xda, 0x6c, 0x53, 0xfd, 0xe3, 0x18, 0x0c, 0xa7, 0xd4, + 0x70, 0xc6, 0xd5, 0xd9, 0xc2, 0xbb, 0x08, 0xfd, 0xf4, 0x56, 0x66, 0x21, + 0x68, 0xb5, 0xb5, 0x4c, 0x9b, 0x1d, 0xdb, 0xac, 0xa0, 0xc4, 0x64, 0x1e, + 0xee, 0x1b, 0xe0, 0xc8, 0x84, 0xc5, 0xa9, 0xd0, 0x50, 0xd8, 0xb6, 0xd2, + 0xb5, 0x1f, 0xbc, 0xf7, 0x01, 0xd2, 0x53, 0x44, 0xc9, 0x1c, 0xae, 0x45, + 0x28, 0xbd, 0xbe, 0x28, 0x6e, 0xb9, 0x06, 0xd6, 0xc9, 0xcd, 0x5a, 0xdd, + 0x31, 0x99, 0x56, 0x22, 0xf0, 0xd7, 0xa4, 0xb3, 0x38, 0x04, 0xcc, 0x7f, + 0x45, 0xba, 0x05, 0x26, 0xf9, 0x34, 0x50, 0xb4, 0xcf, 0xf3, 0x81, 0xb7, + 0xf9, 0xf1, 0x2a, 0xbc, 0x2e, 0xe1, 0x51, 0x12, 0x23, 0x5a, 0xec, 0xe8, + 0x59, 0x1b, 0xb2, 0x58, 0x6e, 0x17, 0x3c, 0x9e, 0x3a, 0x24, 0xf2, 0x7d, + 0xd8, 0xfa, 0x82, 0xf5, 0x30, 0x13, 0x53, 0xf5, 0x6e, 0x08, 0xdd, 0x0d, + 0x92, 0x24, 0x84, 0x02, 0x7b, 0x64, 0x55, 0x1c, 0xda, 0xf4, 0xb7, 0xc1, + 0x35, 0x87, 0xd2, 0x79, 0xf4, 0x34, 0xc3, 0xb7, 0x58, 0xdb, 0x8b, 0x82, + 0x71, 0x49, 0xc1, 0x85, 0x7f, 0x56, 0x8a, 0xf7, 0xaf, 0xbb, 0xd6, 0x38, + 0x38, 0x34, 0x4b, 0x93, 0xe9, 0x77, 0x37, 0xd0, 0x9c, 0xd2, 0xe0, 0x76, + 0x6f, 0xa2, 0x20, 0x2e, 0x0a, 0x2e, 0x48, 0x5e, 0xa2, 0x83, 0xd2, 0xfa, + 0xc2, 0xc8, 0xd9, 0xa7, 0xcd, 0x7b, 0xb3, 0x78, 0x30, 0x46, 0x7e, 0x83, + 0xbc, 0x11, 0x40, 0xbc}; + + static const uint8_t tv_mhash[32] = { + 0x21, 0x83, 0x9d, 0xb5, 0x7b, 0xe2, 0x84, 0xc2, 0x31, 0xf7, 0xb6, + 0xa1, 0x90, 0x9b, 0x53, 0x99, 0x5f, 0x09, 0x1b, 0x84, 0xf7, 0x35, + 0x57, 0xbb, 0xbb, 0xef, 0x7f, 0x7b, 0x93, 0xe8, 0xef, 0x16}; + + ASSERT(mg_rsa_verify(tv_em, 256, tv_mhash)); + { + uint8_t em[256]; + int r = mg_rsa_mod_pow(tv_n, sizeof(tv_n), tv_e, sizeof(tv_e), tv_sig, + sizeof(tv_sig), em, sizeof(em)); + ASSERT(r == 0); + ASSERT(memcmp(em, tv_em, 256) == 0); + ASSERT(mg_rsa_verify(em, 256, tv_mhash)); + } + + { + uint8_t mhash[32]; + uint8_t em[256]; + memcpy(mhash, tv_mhash, 32); + memcpy(em, tv_em, 256); + mhash[0] ^= 0x01; // wrong mhash + ASSERT(!mg_rsa_verify(tv_em, 256, mhash)); + mhash[0] = tv_mhash[0]; + em[255] ^= 0x01; // bad trailer + ASSERT(!mg_rsa_verify(em, 256, tv_mhash)); + em[255] = tv_em[255]; + em[0] |= 0x80; // top bit set + ASSERT(!mg_rsa_verify(em, 256, tv_mhash)); + em[0] = tv_em[0]; + em[223] ^= 0xFF; // corrupt h field + ASSERT(!mg_rsa_verify(em, 256, tv_mhash)); + em[223] = tv_em[223]; + em[50] ^= 0x01; // corrupt zero padding + ASSERT(!mg_rsa_verify(em, 256, tv_mhash)); + em[50] = tv_em[50]; + } #endif } @@ -5148,7 +5261,6 @@ static void test_modbus(void) { mg_mgr_free(&mgr); } - struct wudata { struct mg_mgr *mgr; unsigned long conn_id; // Parent connection ID @@ -5192,11 +5304,16 @@ static void test_wakeup(void) { #endif } +extern uint64_t mg_boot_timestamp_ms; + int main(void) { const char *debug_level = getenv("V"); if (debug_level == NULL) debug_level = "3"; mg_log_set(atoi(debug_level)); + // make sure there is a time reference for mg_now() regardless of SNTP tests + mg_boot_timestamp_ms = (uint64_t) time(NULL) * 1000; + s_error = false; test_modbus(); DASHBOARD("modbus"); diff --git a/tutorials/mqtt/mqtt-server/main.c b/tutorials/mqtt/mqtt-server/main.c index 226f34ac..89769de6 100644 --- a/tutorials/mqtt/mqtt-server/main.c +++ b/tutorials/mqtt/mqtt-server/main.c @@ -31,7 +31,7 @@ static size_t mg_mqtt_next_topic(struct mg_mqtt_message *msg, size_t pos) { unsigned char *buf = (unsigned char *) msg->dgram.buf + pos; size_t new_pos; - if (pos >= msg->dgram.len) return 0; + if (pos + 2 > msg->dgram.len) return 0; topic->len = (size_t) (((unsigned) buf[0]) << 8 | buf[1]); topic->buf = (char *) buf + 2; @@ -77,7 +77,8 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { uint8_t qos, resp[256]; struct mg_str topic; int num_topics = 0; - while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) { + while (num_topics < sizeof(resp) && + (pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) { struct sub *sub = (struct sub *)calloc(1, sizeof(*sub)); sub->c = c; sub->topic = mg_strdup(topic);
Name" "ModifiedSize

..[DIR]