Commit 807a078048 for bind

commit 807a07804863c5cf5f6ce948092b361c6ace3921
Author: Aydın Mercan <aydin@isc.org>
Date:   Thu Apr 30 13:46:27 2026 +0300

    use `isc_parse_*` for standalone strings

    Replace the `strtoul` and `strtol` calls to strings that only contain
    the number with functions from `isc/parseint.h`

diff --git a/bin/check/named-checkzone.c b/bin/check/named-checkzone.c
index ad70b73b8d..6df54c8ab8 100644
--- a/bin/check/named-checkzone.c
+++ b/bin/check/named-checkzone.c
@@ -474,11 +474,9 @@ main(int argc, char **argv) {
 		} else if ((rawver = isc_string_casestripprefix(
 				    outputformatstr, "raw=")) != NULL)
 		{
-			char *end;
-
 			outputformat = dns_masterformat_raw;
-			rawversion = strtol(rawver, &end, 10);
-			if (end == rawver || *end != '\0' || rawversion > 1U) {
+			result = isc_parse_uint32(&rawversion, rawver, 10);
+			if (result != ISC_R_SUCCESS || rawversion > 1U) {
 				fprintf(stderr, "unknown raw format version\n");
 				exit(EXIT_FAILURE);
 			}
diff --git a/bin/confgen/rndc-confgen.c b/bin/confgen/rndc-confgen.c
index 9f5e773c34..274d803775 100644
--- a/bin/confgen/rndc-confgen.c
+++ b/bin/confgen/rndc-confgen.c
@@ -34,6 +34,7 @@
 #include <isc/lib.h>
 #include <isc/mem.h>
 #include <isc/net.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/time.h>
@@ -85,6 +86,7 @@ Usage:\n\
 int
 main(int argc, char **argv) {
 	bool show_final_mem = false;
+	isc_result_t result;
 	isc_buffer_t key_txtbuffer;
 	char key_txtsecret[256];
 	char namebuf[DNS_NAME_FORMATSIZE];
@@ -92,9 +94,8 @@ main(int argc, char **argv) {
 	const char *serveraddr = NULL;
 	dns_secalg_t alg;
 	const char *algname;
-	char *p;
 	int ch;
-	int port;
+	uint16_t port;
 	int keysize = -1;
 	struct in_addr addr4_dummy;
 	struct in6_addr addr6_dummy;
@@ -130,8 +131,9 @@ main(int argc, char **argv) {
 			}
 			break;
 		case 'b':
-			keysize = strtol(isc_commandline_argument, &p, 10);
-			if (*p != '\0' || keysize < 0) {
+			result = isc_parse_signed_number(
+				&keysize, isc_commandline_argument, 10);
+			if (result != ISC_R_SUCCESS || keysize < 0) {
 				fatal("-b requires a non-negative number");
 			}
 			break;
@@ -153,8 +155,9 @@ main(int argc, char **argv) {
 			show_final_mem = true;
 			break;
 		case 'p':
-			port = strtol(isc_commandline_argument, &p, 10);
-			if (*p != '\0' || port < 0 || port > 65535) {
+			result = isc_parse_unsigned_number(
+				&port, isc_commandline_argument, 10);
+			if (result != ISC_R_SUCCESS) {
 				fatal("port '%s' out of range",
 				      isc_commandline_argument);
 			}
diff --git a/bin/dig/host.c b/bin/dig/host.c
index 5ccb702c17..bedd29da92 100644
--- a/bin/dig/host.c
+++ b/bin/dig/host.c
@@ -24,6 +24,7 @@
 #include <isc/lib.h>
 #include <isc/loop.h>
 #include <isc/netaddr.h>
+#include <isc/parseint.h>
 #include <isc/string.h>
 #include <isc/util.h>

@@ -675,9 +676,8 @@ parse_args(bool is_batchfile, int argc, char **argv) {
 			    NULL)
 			{
 				rdtype = dns_rdatatype_ixfr;
-				/* XXXMPA add error checking */
-				serial = strtoul(ixfrserial, NULL, 10);
-				result = ISC_R_SUCCESS;
+				result = isc_parse_uint32(&serial, ixfrserial,
+							  10);
 			} else {
 				tr.base = isc_commandline_argument;
 				tr.length = strlen(isc_commandline_argument);
diff --git a/bin/dnssec/dnssec-cds.c b/bin/dnssec/dnssec-cds.c
index 75f0e0fecc..99d4ed7c3f 100644
--- a/bin/dnssec/dnssec-cds.c
+++ b/bin/dnssec/dnssec-cds.c
@@ -32,6 +32,7 @@
 #include <isc/lib.h>
 #include <isc/log.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/serial.h>
 #include <isc/string.h>
@@ -1063,8 +1064,8 @@ main(int argc, char *argv[]) {
 	bool prefer_cdnskey = false;
 	bool nsupdate = false;
 	uint32_t ttl = 0;
+	isc_result_t result;
 	int ch;
-	char *endp;

 	setfatalcallback(cleanup);

@@ -1122,8 +1123,9 @@ main(int argc, char *argv[]) {
 			version(isc_commandline_progname);
 			break;
 		case 'v':
-			verbose = strtoul(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c
index fd9674f0b0..c8fe4c5cdf 100644
--- a/bin/dnssec/dnssec-dsfromkey.c
+++ b/bin/dnssec/dnssec-dsfromkey.c
@@ -25,6 +25,7 @@
 #include <isc/lib.h>
 #include <isc/log.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -370,7 +371,7 @@ int
 main(int argc, char **argv) {
 	char *classname = NULL;
 	char *filename = NULL, *dir = NULL, *namestr;
-	char *endp, *arg1;
+	char *arg1;
 	int ch;
 	bool cds = false;
 	bool usekeyset = false;
@@ -430,8 +431,9 @@ main(int argc, char **argv) {
 			ttl = strtottl(isc_commandline_argument);
 			break;
 		case 'v':
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c
index 26416cb463..adff481413 100644
--- a/bin/dnssec/dnssec-importkey.c
+++ b/bin/dnssec/dnssec-importkey.c
@@ -23,6 +23,7 @@
 #include <isc/lib.h>
 #include <isc/log.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -297,7 +298,6 @@ int
 main(int argc, char **argv) {
 	char *classname = NULL;
 	char *filename = NULL, *dir = NULL, *namestr;
-	char *endp = NULL;
 	int ch;
 	isc_result_t result;
 	dns_rdataset_t rdataset;
@@ -370,8 +370,10 @@ main(int argc, char **argv) {
 			filename = isc_commandline_argument;
 			break;
 		case 'v':
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			if (isc_parse_signed_number(&verbose,
+						    isc_commandline_argument,
+						    0) != ISC_R_SUCCESS)
+			{
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
index 4aeb58a5a4..fc2f5b549a 100644
--- a/bin/dnssec/dnssec-keyfromlabel.c
+++ b/bin/dnssec/dnssec-keyfromlabel.c
@@ -39,6 +39,7 @@
 #include <dst/dst.h>

 #include "dnssectool.h"
+#include "isc/parseint.h"

 #define MAX_RSA 4096 /* should be long enough... */

@@ -201,9 +202,9 @@ main(int argc, char **argv) {
 			if (*endp != ':' || ul > 0xffff) {
 				fatal("-M range invalid");
 			}
-			tag_max = ul = strtoul(endp + 1, &endp, 10);
-			if (*endp != '\0' || ul > 0xffff || tag_max <= tag_min)
-			{
+			result = isc_parse_unsigned_number(&tag_max, endp + 1,
+							   10);
+			if (result != ISC_R_SUCCESS || tag_max <= tag_min) {
 				fatal("-M range invalid");
 			}
 			break;
@@ -218,8 +219,9 @@ main(int argc, char **argv) {
 			fatal("The -t option has been deprecated.");
 			break;
 		case 'v':
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
index ed307c6093..9a90171c6b 100644
--- a/bin/dnssec/dnssec-keygen.c
+++ b/bin/dnssec/dnssec-keygen.c
@@ -42,6 +42,7 @@
 #include <isc/lib.h>
 #include <isc/log.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/region.h>
 #include <isc/result.h>
 #include <isc/string.h>
@@ -786,8 +787,9 @@ main(int argc, char **argv) {
 			algname = isc_commandline_argument;
 			break;
 		case 'b':
-			ctx.size = strtol(isc_commandline_argument, &endp, 10);
-			if (*endp != '\0' || ctx.size < 0) {
+			result = isc_parse_signed_number(
+				&ctx.size, isc_commandline_argument, 10);
+			if (result != ISC_R_SUCCESS || ctx.size < 0) {
 				fatal("-b requires a non-negative number");
 			}
 			break;
@@ -844,8 +846,8 @@ main(int argc, char **argv) {
 			if (*endp != ':' || ul > 0xffff) {
 				fatal("-M range invalid");
 			}
-			ctx.tag_max = ul = strtoul(endp + 1, &endp, 10);
-			if (*endp != '\0' || ul > 0xffff ||
+			result = isc_parse_uint16(&ctx.tag_max, endp + 1, 10);
+			if (result != ISC_R_SUCCESS ||
 			    ctx.tag_max <= ctx.tag_min)
 			{
 				fatal("-M range invalid");
@@ -883,9 +885,9 @@ main(int argc, char **argv) {
 			fatal("The -t option has been deprecated.");
 			break;
 		case 'v':
-			endp = NULL;
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-ksr.c b/bin/dnssec/dnssec-ksr.c
index 6346fe967b..a3ecfacce7 100644
--- a/bin/dnssec/dnssec-ksr.c
+++ b/bin/dnssec/dnssec-ksr.c
@@ -23,6 +23,7 @@
 #include <isc/lex.h>
 #include <isc/lib.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>

 #include <dns/callbacks.h>
 #include <dns/dnssec.h>
@@ -1304,7 +1305,6 @@ main(int argc, char *argv[]) {
 	isc_result_t result;
 	isc_buffer_t buf;
 	int ch;
-	char *endp;
 	ksr_ctx_t ksr = {
 		.now = isc_stdtime_now(),
 	};
@@ -1359,8 +1359,9 @@ main(int argc, char *argv[]) {
 			version(isc_commandline_progname);
 			break;
 		case 'v':
-			verbose = strtoul(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c
index 74d6210be2..34441d083a 100644
--- a/bin/dnssec/dnssec-revoke.c
+++ b/bin/dnssec/dnssec-revoke.c
@@ -25,6 +25,7 @@
 #include <isc/hash.h>
 #include <isc/lib.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -66,7 +67,6 @@ main(int argc, char **argv) {
 	char *dir = NULL;
 	char newname[1024], oldname[1024];
 	char keystr[DST_KEY_FORMATSIZE];
-	char *endp;
 	int ch;
 	dst_key_t *key = NULL;
 	uint32_t flags;
@@ -106,8 +106,10 @@ main(int argc, char **argv) {
 			id = true;
 			break;
 		case 'v':
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			if (isc_parse_signed_number(&verbose,
+						    isc_commandline_argument,
+						    0) != ISC_R_SUCCESS)
+			{
 				fatal("-v must be followed by a number");
 			}
 			break;
diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c
index 09bddc75cf..050f5c3ed3 100644
--- a/bin/dnssec/dnssec-settime.c
+++ b/bin/dnssec/dnssec-settime.c
@@ -28,6 +28,7 @@
 #include <isc/lib.h>
 #include <isc/log.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/time.h>
@@ -185,7 +186,6 @@ main(int argc, char **argv) {
 	const char *filename = NULL;
 	char *directory = NULL;
 	char keystr[DST_KEY_FORMATSIZE];
-	char *endp;
 	const char *p, *tail;
 	int ch;
 	const char *predecessor = NULL;
@@ -522,10 +522,13 @@ main(int argc, char **argv) {
 			/* Does not return. */
 			version(isc_commandline_progname);
 		case 'v':
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			if (isc_parse_signed_number(&verbose,
+						    isc_commandline_argument,
+						    0) != ISC_R_SUCCESS)
+			{
 				fatal("-v must be followed by a number");
 			}
+
 			break;
 		case 'z':
 			if (setzrrsig) {
diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c
index db8199765d..da3a2fb848 100644
--- a/bin/dnssec/dnssec-signzone.c
+++ b/bin/dnssec/dnssec-signzone.c
@@ -53,6 +53,7 @@
 #include <isc/mem.h>
 #include <isc/mutex.h>
 #include <isc/os.h>
+#include <isc/parseint.h>
 #include <isc/random.h>
 #include <isc/result.h>
 #include <isc/rwlock.h>
@@ -3289,7 +3290,6 @@ main(int argc, char *argv[]) {
 	char *serialformatstr = NULL;
 	char *dskeyfile[MAXDSKEYS];
 	int ndskeys = 0;
-	char *endp;
 	isc_time_t timer_start, timer_finish;
 	isc_time_t sign_start, sign_finish;
 	isc_result_t result, vresult;
@@ -3431,8 +3431,9 @@ main(int argc, char *argv[]) {
 				no_max_check = true;
 				break;
 			}
-			nsec3iter = strtoul(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_unsigned_number(
+				&nsec3iter, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("iterations must be numeric");
 			}
 			if (nsec3iter > 0xffffU) {
@@ -3445,18 +3446,18 @@ main(int argc, char *argv[]) {
 			break;

 		case 'i':
-			endp = NULL;
-			cycle = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0' || cycle < 0) {
+			result = isc_parse_signed_number(
+				&cycle, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS || cycle < 0) {
 				fatal("cycle period must be numeric and "
 				      "positive");
 			}
 			break;

 		case 'j':
-			endp = NULL;
-			jitter = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0' || jitter < 0) {
+			result = isc_parse_signed_number(
+				&jitter, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS || jitter < 0) {
 				fatal("jitter must be numeric and positive");
 			}
 			break;
@@ -3478,9 +3479,9 @@ main(int argc, char *argv[]) {

 		case 'L':
 			snset = true;
-			endp = NULL;
-			serialnum = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_unsigned_number(
+				&serialnum, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fprintf(stderr, "source serial number "
 						"must be numeric");
 				exit(EXIT_FAILURE);
@@ -3488,10 +3489,10 @@ main(int argc, char *argv[]) {
 			break;

 		case 'M':
-			endp = NULL;
 			set_maxttl = true;
-			maxttl = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_unsigned_number(
+				&maxttl, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fprintf(stderr, "maximum TTL "
 						"must be numeric");
 				exit(EXIT_FAILURE);
@@ -3506,9 +3507,9 @@ main(int argc, char *argv[]) {
 			break;

 		case 'n':
-			endp = NULL;
-			nloops = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0' || nloops > INT32_MAX) {
+			result = isc_parse_unsigned_number(
+				&nloops, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS || nloops > INT32_MAX) {
 				fatal("number of cpus must be numeric");
 			}
 			break;
@@ -3550,7 +3551,6 @@ main(int argc, char *argv[]) {
 			break;

 		case 'T':
-			endp = NULL;
 			set_keyttl = true;
 			keyttl = strtottl(isc_commandline_argument);
 			break;
@@ -3568,9 +3568,9 @@ main(int argc, char *argv[]) {
 			break;

 		case 'v':
-			endp = NULL;
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("verbose level must be numeric");
 			}
 			break;
@@ -3721,11 +3721,9 @@ main(int argc, char *argv[]) {
 		} else if ((rawver = isc_string_casestripprefix(
 				    outputformatstr, "raw=")) != NULL)
 		{
-			char *end;
-
 			outputformat = dns_masterformat_raw;
-			rawversion = strtol(rawver, &end, 10);
-			if (end == rawver || *end != '\0' || rawversion > 1U) {
+			result = isc_parse_uint32(&rawversion, rawver, 10);
+			if (result != ISC_R_SUCCESS || rawversion > 1U) {
 				fprintf(stderr, "unknown raw format version\n");
 				exit(EXIT_FAILURE);
 			}
diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c
index 1f92b59006..b5afdfd1a0 100644
--- a/bin/dnssec/dnssec-verify.c
+++ b/bin/dnssec/dnssec-verify.c
@@ -28,6 +28,7 @@
 #include <isc/mem.h>
 #include <isc/mutex.h>
 #include <isc/os.h>
+#include <isc/parseint.h>
 #include <isc/random.h>
 #include <isc/result.h>
 #include <isc/rwlock.h>
@@ -166,7 +167,6 @@ main(int argc, char *argv[]) {
 	isc_result_t result;
 	char *classname = NULL;
 	dns_rdataclass_t rdclass;
-	char *endp;
 	int ch;
 	bool origin_is_file = false;

@@ -227,9 +227,9 @@ main(int argc, char *argv[]) {
 			break;

 		case 'v':
-			endp = NULL;
-			verbose = strtol(isc_commandline_argument, &endp, 0);
-			if (*endp != '\0') {
+			result = isc_parse_signed_number(
+				&verbose, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fatal("verbose level must be numeric");
 			}
 			break;
diff --git a/bin/named/main.c b/bin/named/main.c
index 56ecb63b89..6a6a9bea88 100644
--- a/bin/named/main.c
+++ b/bin/named/main.c
@@ -38,6 +38,7 @@
 #include <isc/managers.h>
 #include <isc/netmgr.h>
 #include <isc/os.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/signal.h>
 #include <isc/stdio.h>
@@ -359,16 +360,13 @@ add_ellipsis:

 static int
 parse_int(const char *arg, const char *desc) {
-	char *endp;
 	int tmp;
-	long int ltmp;

-	ltmp = strtol(arg, &endp, 10);
-	tmp = (int)ltmp;
-	if (*endp != '\0') {
+	if (isc_parse_signed_number(&tmp, arg, 10) != ISC_R_SUCCESS) {
 		named_main_earlyfatal("%s '%s' must be numeric", desc, arg);
 	}
-	if (tmp < 0 || tmp != ltmp) {
+
+	if (tmp < 0) {
 		named_main_earlyfatal("%s '%s' out of range", desc, arg);
 	}
 	return tmp;
diff --git a/bin/named/server.c b/bin/named/server.c
index 5122ec96a6..83398cbdcb 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -11282,9 +11282,8 @@ cleanup:

 isc_result_t
 named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
+	typeof(named_g_debuglevel) newlevel;
 	char *ptr;
-	char *endp;
-	long newlevel;

 	UNUSED(server);

@@ -11301,11 +11300,11 @@ named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
 			named_g_debuglevel++;
 		}
 	} else {
-		newlevel = strtol(ptr, &endp, 10);
-		if (*endp != '\0' || newlevel < 0 || newlevel > 99) {
+		RETERR(isc_parse_unsigned_number(&newlevel, ptr, 10));
+		if (newlevel > 99) {
 			return ISC_R_RANGE;
 		}
-		named_g_debuglevel = (unsigned int)newlevel;
+		named_g_debuglevel = newlevel;
 	}
 	isc_log_setdebuglevel(named_g_debuglevel);
 	isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
index 5458649b9b..dde58e8380 100644
--- a/bin/nsupdate/nsupdate.c
+++ b/bin/nsupdate/nsupdate.c
@@ -1573,7 +1573,7 @@ evaluate_lease(char *cmdline) {
 static uint16_t
 evaluate_server(char *cmdline) {
 	char *word, *server;
-	long port;
+	uint16_t port;

 	if (local_only) {
 		fprintf(stderr, "cannot reset server in localhost-only mode\n");
@@ -1591,17 +1591,20 @@ evaluate_server(char *cmdline) {
 	if (word == NULL || *word == 0) {
 		port = dnsport;
 	} else {
-		char *endp;
-		port = strtol(word, &endp, 10);
-		if (*endp != 0) {
+		switch (isc_parse_uint16(&port, word, 10)) {
+		case ISC_R_BADNUMBER:
 			fprintf(stderr, "port '%s' is not numeric\n", word);
 			return STATUS_SYNTAX;
-		} else if (port < 1 || port > 65535) {
+		case ISC_R_RANGE:
 			fprintf(stderr,
 				"port '%s' is out of range "
 				"(1 to 65535)\n",
 				word);
 			return STATUS_SYNTAX;
+		case ISC_R_SUCCESS:
+			break;
+		default:
+			UNREACHABLE();
 		}
 	}

@@ -1629,7 +1632,7 @@ evaluate_server(char *cmdline) {
 static uint16_t
 evaluate_local(char *cmdline) {
 	char *word, *local;
-	long port;
+	uint16_t port;
 	struct in_addr in4;
 	struct in6_addr in6;

@@ -1644,17 +1647,20 @@ evaluate_local(char *cmdline) {
 	if (word == NULL || *word == 0) {
 		port = 0;
 	} else {
-		char *endp;
-		port = strtol(word, &endp, 10);
-		if (*endp != 0) {
+		switch (isc_parse_uint16(&port, word, 10)) {
+		case ISC_R_BADNUMBER:
 			fprintf(stderr, "port '%s' is not numeric\n", word);
 			return STATUS_SYNTAX;
-		} else if (port < 1 || port > 65535) {
+		case ISC_R_RANGE:
 			fprintf(stderr,
 				"port '%s' is out of range "
 				"(1 to 65535)\n",
 				word);
 			return STATUS_SYNTAX;
+		case ISC_R_SUCCESS:
+			break;
+		default:
+			UNREACHABLE();
 		}
 	}

diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c
index 652f9dd649..a1483a1716 100644
--- a/bin/rndc/rndc.c
+++ b/bin/rndc/rndc.c
@@ -29,6 +29,7 @@
 #include <isc/mem.h>
 #include <isc/net.h>
 #include <isc/netmgr.h>
+#include <isc/parseint.h>
 #include <isc/random.h>
 #include <isc/refcount.h>
 #include <isc/result.h>
@@ -846,6 +847,7 @@ int
 main(int argc, char **argv) {
 	bool show_final_mem = false;
 	isc_logconfig_t *logconfig = NULL;
+	isc_result_t result;
 	cfg_obj_t *config = NULL;
 	const char *keyname = NULL;
 	struct in_addr in;
@@ -937,8 +939,11 @@ main(int argc, char **argv) {
 			break;

 		case 't':
-			timeout = strtol(isc_commandline_argument, &p, 10);
-			if (*p != '\0' || timeout < 0 || timeout > 86400) {
+			result = isc_parse_signed_number(
+				&timeout, isc_commandline_argument, 10);
+			if (result != ISC_R_SUCCESS || timeout < 0 ||
+			    timeout > 86400)
+			{
 				fatal("invalid timeout '%s'",
 				      isc_commandline_argument);
 			}
diff --git a/bin/tests/test_client.c b/bin/tests/test_client.c
index 6ae103aff3..c1562b3e05 100644
--- a/bin/tests/test_client.c
+++ b/bin/tests/test_client.c
@@ -31,6 +31,7 @@
 #include <isc/netaddr.h>
 #include <isc/netmgr.h>
 #include <isc/os.h>
+#include <isc/parseint.h>
 #include <isc/sockaddr.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -66,10 +67,11 @@ static isc_tlsctx_t *tls_ctx = NULL;

 static isc_result_t
 parse_port(const char *input) {
-	char *endptr = NULL;
-	long val = strtol(input, &endptr, 10);
+	isc_result_t result;
+	uint16_t value;

-	if ((*endptr != '\0') || (val <= 0) || (val >= 65536)) {
+	result = isc_parse_uint16(&value, input, 10);
+	if (result != ISC_R_SUCCESS || (value == 0)) {
 		return ISC_R_BADNUMBER;
 	}

@@ -110,30 +112,31 @@ parse_address(const char *input) {
 	return ISC_R_BADADDRESSFORM;
 }

-static int
+static isc_result_t
 parse_workers(const char *input) {
-	char *endptr = NULL;
-	long val = strtol(input, &endptr, 10);
+	typeof(workers) value;

-	if ((*endptr != '\0') || (val <= 0) || (val >= 128)) {
+	RETERR(isc_parse_signed_number(&value, input, 10));
+	if (value == 0 || value >= 128) {
 		return ISC_R_BADNUMBER;
 	}

-	workers = val;
+	workers = value;

 	return ISC_R_SUCCESS;
 }

 static isc_result_t
 parse_timeout(const char *input) {
-	char *endptr = NULL;
-	long val = strtol(input, &endptr, 10);
+	isc_result_t result;
+	uint64_t value;

-	if ((*endptr != '\0') || (val <= 0) || (val >= 120)) {
+	result = isc_parse_uint64(&value, input, 10);
+	if (result != ISC_R_SUCCESS || (value == 0) || (value >= 120)) {
 		return ISC_R_BADNUMBER;
 	}

-	timeout = (in_port_t)val * 1000;
+	timeout = (in_port_t)value * 1000;

 	return ISC_R_SUCCESS;
 }
diff --git a/bin/tests/test_server.c b/bin/tests/test_server.c
index ce2b3ec6d0..1dfc41e55d 100644
--- a/bin/tests/test_server.c
+++ b/bin/tests/test_server.c
@@ -25,6 +25,7 @@
 #include <isc/netaddr.h>
 #include <isc/netmgr.h>
 #include <isc/os.h>
+#include <isc/parseint.h>
 #include <isc/sockaddr.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -51,14 +52,15 @@ send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg);

 static isc_result_t
 parse_port(const char *input) {
-	char *endptr = NULL;
-	long val = strtol(input, &endptr, 10);
+	isc_result_t result;
+	typeof(port) value;

-	if ((*endptr != '\0') || (val <= 0) || (val >= 65536)) {
+	result = isc_parse_unsigned_number(&value, input, 10);
+	if (result != ISC_R_SUCCESS || (value == 0)) {
 		return ISC_R_BADNUMBER;
 	}

-	port = (in_port_t)val;
+	port = value;

 	return ISC_R_SUCCESS;
 }
@@ -93,16 +95,16 @@ parse_address(const char *input) {
 	return ISC_R_BADADDRESSFORM;
 }

-static int
+static isc_result_t
 parse_workers(const char *input) {
-	char *endptr = NULL;
-	long val = strtol(input, &endptr, 10);
+	typeof(workers) value;

-	if ((*endptr != '\0') || (val <= 0) || (val >= 128)) {
+	RETERR(isc_parse_signed_number(&value, input, 10));
+	if (value == 0 || value >= 128) {
 		return ISC_R_BADNUMBER;
 	}

-	workers = val;
+	workers = value;

 	return ISC_R_SUCCESS;
 }
diff --git a/bin/tools/named-journalprint.c b/bin/tools/named-journalprint.c
index 0678b03f10..3493cfbf40 100644
--- a/bin/tools/named-journalprint.c
+++ b/bin/tools/named-journalprint.c
@@ -19,6 +19,7 @@
 #include <isc/lib.h>
 #include <isc/log.h>
 #include <isc/mem.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/util.h>

@@ -54,7 +55,6 @@ main(int argc, char **argv) {
 	bool downgrade = false;
 	bool upgrade = false;
 	unsigned int serial = 0;
-	char *endp = NULL;

 	isc_commandline_init(argc, argv);

@@ -62,8 +62,9 @@ main(int argc, char **argv) {
 		switch (ch) {
 		case 'c':
 			compact = true;
-			serial = strtoul(isc_commandline_argument, &endp, 0);
-			if (endp == isc_commandline_argument || *endp != 0) {
+			result = isc_parse_unsigned_number(
+				&serial, isc_commandline_argument, 0);
+			if (result != ISC_R_SUCCESS) {
 				fprintf(stderr, "invalid serial: %s\n",
 					isc_commandline_argument);
 				exit(EXIT_FAILURE);
diff --git a/lib/dns/gen.c b/lib/dns/gen.c
index 184267a848..eb2ad120e4 100644
--- a/lib/dns/gen.c
+++ b/lib/dns/gen.c
@@ -751,6 +751,7 @@ main(int argc, char **argv) {

 		printf("#include <stdbool.h>\n");
 		printf("#include <isc/result.h>\n\n");
+		printf("#include <isc/parseint.h>\n\n");
 		printf("#include <dns/name.h>\n\n");

 		for (tt = types; tt != NULL; tt = tt->next) {
diff --git a/lib/dns/geoip2.c b/lib/dns/geoip2.c
index b0c1746c26..b9be33d8de 100644
--- a/lib/dns/geoip2.c
+++ b/lib/dns/geoip2.c
@@ -27,6 +27,7 @@
 #include <isc/log.h>
 #include <isc/mem.h>
 #include <isc/once.h>
+#include <isc/parseint.h>
 #include <isc/sockaddr.h>
 #include <isc/string.h>
 #include <isc/thread.h>
@@ -348,8 +349,10 @@ dns_geoip_match(const isc_netaddr_t *reqaddr,
 			if (tail != NULL) {
 				s = tail;
 			}
-			i = strtol(s, NULL, 10);
-			return match_int(&value, i);
+			if (isc_parse_signed_number(&i, s, 10) == ISC_R_SUCCESS)
+			{
+				return match_int(&value, i);
+			}
 		}
 		break;

diff --git a/lib/dns/name.c b/lib/dns/name.c
index 96901985be..c37d0ffe39 100644
--- a/lib/dns/name.c
+++ b/lib/dns/name.c
@@ -26,6 +26,7 @@
 #include <isc/hex.h>
 #include <isc/mem.h>
 #include <isc/once.h>
+#include <isc/parseint.h>
 #include <isc/random.h>
 #include <isc/result.h>
 #include <isc/string.h>
@@ -1995,6 +1996,7 @@ bool
 dns_name_isdnssvcb(const dns_name_t *name) {
 	unsigned char len, len1;
 	const unsigned char *ndata;
+	isc_result_t result;

 	REQUIRE(DNS_NAME_VALID(name));

@@ -2012,8 +2014,7 @@ dns_name_isdnssvcb(const dns_name_t *name) {
 	}
 	if (isdigit(ndata[1]) && name->length > len + 1) {
 		char buf[sizeof("65000")];
-		long port;
-		char *endp;
+		uint16_t port;

 		/*
 		 * Do we have a valid _port label?
@@ -2023,8 +2024,8 @@ dns_name_isdnssvcb(const dns_name_t *name) {
 		}
 		memcpy(buf, ndata + 1, len - 1);
 		buf[len - 1] = 0;
-		port = strtol(buf, &endp, 10);
-		if (*endp != 0 || port < 0 || port > 0xffff) {
+		result = isc_parse_uint16(&port, buf, 10);
+		if (result != ISC_R_SUCCESS) {
 			return false;
 		}

@@ -2050,8 +2051,10 @@ bool
 dns_name__israd(const dns_name_t *name, const dns_name_t *rad) {
 	dns_name_t suffix;
 	char labelbuf[64];
+	isc_result_t result;
 	unsigned long v, last = ULONG_MAX;
 	char *end, *l;
+	uint64_t u64;

 	REQUIRE(DNS_NAME_VALID(name));
 	REQUIRE(DNS_NAME_VALID(rad));
@@ -2109,8 +2112,9 @@ dns_name__israd(const dns_name_t *name, const dns_name_t *rad) {
 	if (strlen(labelbuf) != *suffix.ndata) {
 		return false;
 	}
-	v = strtoul(labelbuf, &end, 10);
-	if (v > 0xfff || *end != 0) {
+
+	result = isc_parse_unsigned_number(&u64, labelbuf, 10);
+	if (result != ISC_R_SUCCESS || u64 > 0xfff) {
 		return false;
 	}

diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c
index 3d7ede50c7..423a915f6f 100644
--- a/lib/dns/rdata.c
+++ b/lib/dns/rdata.c
@@ -1496,8 +1496,6 @@ dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
 	    strncasecmp("type", source->base, 4) == 0)
 	{
 		char buf[sizeof("65000")];
-		char *endp;
-		unsigned int val;

 		/*
 		 * source->base is not required to be NUL terminated.
@@ -1505,11 +1503,8 @@ dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
 		 */
 		snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 4),
 			 source->base + 4);
-		val = strtoul(buf, &endp, 10);
-		if (*endp == '\0' && val <= 0xffff) {
-			*typep = (dns_rdatatype_t)val;
-			return ISC_R_SUCCESS;
-		}
+		RETERR(isc_parse_unsigned_number(typep, buf, 10));
+		return ISC_R_SUCCESS;
 	}

 	return DNS_R_UNKNOWN;
diff --git a/lib/dns/rdata/any_255/tsig_250.c b/lib/dns/rdata/any_255/tsig_250.c
index dfba8bbf47..78cbd416d3 100644
--- a/lib/dns/rdata/any_255/tsig_250.c
+++ b/lib/dns/rdata/any_255/tsig_250.c
@@ -23,8 +23,6 @@ fromtext_any_tsig(ARGS_FROMTEXT) {
 	uint64_t sigtime;
 	isc_buffer_t buffer;
 	dns_rcode_t rcode;
-	long i;
-	char *e;

 	REQUIRE(type == dns_rdatatype_tsig);
 	REQUIRE(rdclass == dns_rdataclass_any);
@@ -49,10 +47,7 @@ fromtext_any_tsig(ARGS_FROMTEXT) {
 	 */
 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
 				      false));
-	sigtime = strtoull(DNS_AS_STR(token), &e, 10);
-	if (*e != 0) {
-		RETTOK(DNS_R_SYNTAX);
-	}
+	RETTOK(isc_parse_uint64(&sigtime, DNS_AS_STR(token), 10));
 	if ((sigtime >> 48) != 0) {
 		RETTOK(ISC_R_RANGE);
 	}
@@ -102,14 +97,7 @@ fromtext_any_tsig(ARGS_FROMTEXT) {
 	if (dns_tsigrcode_fromtext(&rcode, &token.value.as_textregion) !=
 	    ISC_R_SUCCESS)
 	{
-		i = strtol(DNS_AS_STR(token), &e, 10);
-		if (*e != 0) {
-			RETTOK(DNS_R_UNKNOWN);
-		}
-		if (i < 0 || i > 0xffff) {
-			RETTOK(ISC_R_RANGE);
-		}
-		rcode = (dns_rcode_t)i;
+		RETTOK(isc_parse_uint16(&rcode, DNS_AS_STR(token), 10));
 	}
 	RETERR(uint16_tobuffer(rcode, target));

diff --git a/lib/dns/rdata/generic/dsync_66.c b/lib/dns/rdata/generic/dsync_66.c
index 8cd8be20eb..7158574c0a 100644
--- a/lib/dns/rdata/generic/dsync_66.c
+++ b/lib/dns/rdata/generic/dsync_66.c
@@ -47,15 +47,8 @@ fromtext_dsync(ARGS_FROMTEXT) {
 				      false));
 	result = dns_rdatatype_fromtext(&rrtype, &token.value.as_textregion);
 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
-		char *e = NULL;
-		long i = strtol(DNS_AS_STR(token), &e, 10);
-		if (i < 0 || i > 65535) {
-			RETTOK(ISC_R_RANGE);
-		}
-		if (*e != 0) {
-			RETTOK(result);
-		}
-		rrtype = (dns_rdatatype_t)i;
+		RETTOK(isc_parse_unsigned_number(&rrtype, DNS_AS_STR(token),
+						 10));
 	}
 	RETERR(uint16_tobuffer(rrtype, target));

diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c
index 386f2755d2..3540dbdc30 100644
--- a/lib/dns/rdata/generic/rrsig_46.c
+++ b/lib/dns/rdata/generic/rrsig_46.c
@@ -24,9 +24,7 @@ static isc_result_t
 fromtext_rrsig(ARGS_FROMTEXT) {
 	isc_token_t token;
 	unsigned char alg, labels;
-	long i;
 	dns_rdatatype_t covered;
-	char *e = NULL;
 	isc_result_t result;
 	isc_buffer_t buffer;
 	uint32_t time_signed, time_expire;
@@ -47,14 +45,7 @@ fromtext_rrsig(ARGS_FROMTEXT) {
 				      false));
 	result = dns_rdatatype_fromtext(&covered, &token.value.as_textregion);
 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
-		i = strtol(DNS_AS_STR(token), &e, 10);
-		if (i < 0 || i > 65535) {
-			RETTOK(ISC_R_RANGE);
-		}
-		if (*e != 0) {
-			RETTOK(result);
-		}
-		covered = (dns_rdatatype_t)i;
+		RETTOK(isc_parse_uint16(&covered, DNS_AS_STR(token), 10));
 	}
 	RETERR(uint16_tobuffer(covered, target));

@@ -92,18 +83,7 @@ fromtext_rrsig(ARGS_FROMTEXT) {
 	if (token.value.as_textregion.length <= 10U &&
 	    *DNS_AS_STR(token) != '-' && *DNS_AS_STR(token) != '+')
 	{
-		char *end;
-		unsigned long u;
-		uint64_t u64;
-
-		u64 = u = strtoul(DNS_AS_STR(token), &end, 10);
-		if (u == ULONG_MAX || *end != 0) {
-			RETTOK(DNS_R_SYNTAX);
-		}
-		if (u64 > 0xffffffffUL) {
-			RETTOK(ISC_R_RANGE);
-		}
-		time_expire = u;
+		RETTOK(isc_parse_uint32(&time_expire, DNS_AS_STR(token), 10));
 	} else {
 		RETTOK(dns_time32_fromregion(token.value.as_textregion,
 					     &time_expire));
@@ -118,18 +98,7 @@ fromtext_rrsig(ARGS_FROMTEXT) {
 	if (token.value.as_textregion.length <= 10U &&
 	    *DNS_AS_STR(token) != '-' && *DNS_AS_STR(token) != '+')
 	{
-		char *end;
-		unsigned long u;
-		uint64_t u64;
-
-		u64 = u = strtoul(DNS_AS_STR(token), &end, 10);
-		if (u == ULONG_MAX || *end != 0) {
-			RETTOK(DNS_R_SYNTAX);
-		}
-		if (u64 > 0xffffffffUL) {
-			RETTOK(ISC_R_RANGE);
-		}
-		time_signed = u;
+		RETTOK(isc_parse_uint32(&time_signed, DNS_AS_STR(token), 10));
 	} else {
 		RETTOK(dns_time32_fromregion(token.value.as_textregion,
 					     &time_signed));
diff --git a/lib/dns/rdata/generic/sig_24.c b/lib/dns/rdata/generic/sig_24.c
index c2787f72a9..9dd8d3a4ba 100644
--- a/lib/dns/rdata/generic/sig_24.c
+++ b/lib/dns/rdata/generic/sig_24.c
@@ -22,9 +22,7 @@ static isc_result_t
 fromtext_sig(ARGS_FROMTEXT) {
 	isc_token_t token;
 	unsigned char alg, c;
-	long i;
 	dns_rdatatype_t covered;
-	char *e;
 	isc_result_t result;
 	isc_buffer_t buffer;
 	uint32_t time_signed, time_expire;
@@ -43,14 +41,7 @@ fromtext_sig(ARGS_FROMTEXT) {
 				      false));
 	result = dns_rdatatype_fromtext(&covered, &token.value.as_textregion);
 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
-		i = strtol(DNS_AS_STR(token), &e, 10);
-		if (i < 0 || i > 65535) {
-			RETTOK(ISC_R_RANGE);
-		}
-		if (*e != 0) {
-			RETTOK(result);
-		}
-		covered = (dns_rdatatype_t)i;
+		RETTOK(isc_parse_uint16(&covered, DNS_AS_STR(token), 10));
 	}
 	RETERR(uint16_tobuffer(covered, target));

diff --git a/lib/dns/rdata/generic/tkey_249.c b/lib/dns/rdata/generic/tkey_249.c
index dbc7c68c29..fe55be05a8 100644
--- a/lib/dns/rdata/generic/tkey_249.c
+++ b/lib/dns/rdata/generic/tkey_249.c
@@ -23,8 +23,6 @@ fromtext_tkey(ARGS_FROMTEXT) {
 	isc_token_t token;
 	dns_rcode_t rcode;
 	isc_buffer_t buffer;
-	long i;
-	char *e;

 	REQUIRE(type == dns_rdatatype_tkey);

@@ -75,14 +73,7 @@ fromtext_tkey(ARGS_FROMTEXT) {
 	if (dns_tsigrcode_fromtext(&rcode, &token.value.as_textregion) !=
 	    ISC_R_SUCCESS)
 	{
-		i = strtol(DNS_AS_STR(token), &e, 10);
-		if (*e != 0) {
-			RETTOK(DNS_R_UNKNOWN);
-		}
-		if (i < 0 || i > 0xffff) {
-			RETTOK(ISC_R_RANGE);
-		}
-		rcode = (dns_rcode_t)i;
+		RETTOK(isc_parse_uint16(&rcode, DNS_AS_STR(token), 10));
 	}
 	RETERR(uint16_tobuffer(rcode, target));

diff --git a/lib/dns/rdata/in_1/svcb_64.c b/lib/dns/rdata/in_1/svcb_64.c
index 632ebcf973..d2b589f0b4 100644
--- a/lib/dns/rdata/in_1/svcb_64.c
+++ b/lib/dns/rdata/in_1/svcb_64.c
@@ -242,10 +242,9 @@ svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) {
 	isc_buffer_t sb;
 	isc_region_t keyregion;
 	size_t len;
-	uint16_t key;
+	uint16_t key, port;
 	unsigned int i;
 	unsigned int used;
-	unsigned long ul;

 	for (i = 0; i < ARRAY_SIZE(sbpr); i++) {
 		len = strlen(sbpr[i].name);
@@ -284,14 +283,8 @@ svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) {
 			{
 				return DNS_R_SYNTAX;
 			}
-			ul = strtoul(region->base, &e, 10);
-			if (*e != '\0') {
-				return DNS_R_SYNTAX;
-			}
-			if (ul > 0xffff) {
-				return ISC_R_RANGE;
-			}
-			RETERR(uint16_tobuffer(ul, target));
+			RETERR(isc_parse_uint16(&port, region->base, 10));
+			RETERR(uint16_tobuffer(port, target));
 			break;
 		case sbpr_ipv4s:
 			/* Reject embedded NUL bytes. */
diff --git a/lib/dns/rdata/in_1/wks_11.c b/lib/dns/rdata/in_1/wks_11.c
index b53583e1f8..d3560c0e32 100644
--- a/lib/dns/rdata/in_1/wks_11.c
+++ b/lib/dns/rdata/in_1/wks_11.c
@@ -16,6 +16,7 @@

 #include <limits.h>
 #include <netdb.h>
+#include <stdint.h>

 #include <isc/ascii.h>
 #include <isc/net.h>
@@ -31,7 +32,7 @@ init_lock(void) {
 }

 static bool
-mygetprotobyname(const char *name, long *proto) {
+mygetprotobyname(const char *name, int32_t *proto) {
 	struct protoent *pe;

 	LOCK(&wks_lock);
@@ -44,7 +45,7 @@ mygetprotobyname(const char *name, long *proto) {
 }

 static bool
-mygetservbyname(const char *name, const char *proto, long *port) {
+mygetservbyname(const char *name, const char *proto, int32_t *port) {
 	struct servent *se;

 	LOCK(&wks_lock);
@@ -62,10 +63,9 @@ fromtext_in_wks(ARGS_FROMTEXT) {
 	isc_token_t token;
 	isc_region_t region;
 	struct in_addr addr;
-	char *e = NULL;
-	long proto;
+	int32_t proto;
 	unsigned char bm[8 * 1024]; /* 64k bits */
-	long port;
+	int32_t port;
 	long maxport = -1;
 	const char *ps = NULL;
 	unsigned int n;
@@ -105,12 +105,14 @@ fromtext_in_wks(ARGS_FROMTEXT) {
 	CHECK(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
 				     false));

-	proto = strtol(DNS_AS_STR(token), &e, 10);
-	if (*e != '\0' && !mygetprotobyname(DNS_AS_STR(token), &proto)) {
+	result = isc_parse_signed_number(&proto, DNS_AS_STR(token), 10);
+	if (result != ISC_R_SUCCESS &&
+	    !mygetprotobyname(DNS_AS_STR(token), &proto))
+	{
 		CHECKTOK(DNS_R_UNKNOWNPROTO);
 	}

-	if (proto < 0 || proto > 0xff) {
+	if (proto < 0 || proto > UINT8_MAX) {
 		CHECKTOK(ISC_R_RANGE);
 	}

@@ -137,8 +139,9 @@ fromtext_in_wks(ARGS_FROMTEXT) {
 		strlcpy(service, DNS_AS_STR(token), sizeof(service));
 		isc_ascii_strtolower(service);

-		port = strtol(DNS_AS_STR(token), &e, 10);
-		if (*e != 0 && !mygetservbyname(service, ps, &port) &&
+		result = isc_parse_signed_number(&port, DNS_AS_STR(token), 10);
+		if (result != ISC_R_SUCCESS &&
+		    !mygetservbyname(service, ps, &port) &&
 		    !mygetservbyname(DNS_AS_STR(token), ps, &port))
 		{
 			CHECKTOK(DNS_R_UNKNOWNSERVICE);
diff --git a/lib/dns/resconf.c b/lib/dns/resconf.c
index 3679b5dde1..1628b63e40 100644
--- a/lib/dns/resconf.c
+++ b/lib/dns/resconf.c
@@ -47,6 +47,7 @@
 #include <isc/magic.h>
 #include <isc/mem.h>
 #include <isc/netaddr.h>
+#include <isc/parseint.h>
 #include <isc/sockaddr.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -456,22 +457,6 @@ resconf_parsesortlist(irs_resconf_t *conf, FILE *fp) {
 	return ISC_R_SUCCESS;
 }

-static isc_result_t
-resconf_optionnumber(const char *word, uint8_t *number) {
-	char *p;
-	long n;
-
-	n = strtol(word, &p, 10);
-	if (*p != '\0') { /* Bad string. */
-		return ISC_R_UNEXPECTEDTOKEN;
-	}
-	if (n < 0 || n > 0xff) { /* Out of range. */
-		return ISC_R_RANGE;
-	}
-	*number = n;
-	return ISC_R_SUCCESS;
-}
-
 static isc_result_t
 resconf_parseoption(irs_resconf_t *conf, FILE *fp) {
 	int delim;
@@ -490,15 +475,15 @@ resconf_parseoption(irs_resconf_t *conf, FILE *fp) {
 		} else if ((value = isc_string_stripprefix(word, "ndots:")) !=
 			   NULL)
 		{
-			CHECK(resconf_optionnumber(value, &conf->ndots));
+			CHECK(isc_parse_uint8(&conf->ndots, value, 10));
 		} else if ((value = isc_string_stripprefix(word, "attempts"
 								 ":")) != NULL)
 		{
-			CHECK(resconf_optionnumber(value, &conf->attempts));
+			CHECK(isc_parse_uint8(&conf->attempts, value, 10));
 		} else if ((value = isc_string_stripprefix(word, "timeout:")) !=
 			   NULL)
 		{
-			CHECK(resconf_optionnumber(value, &conf->timeout));
+			CHECK(isc_parse_uint8(&conf->timeout, value, 10));
 		}

 		if (delim == EOF || delim == '\n') {
diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c
index 0c94df4f7e..f9baf88032 100644
--- a/lib/isccc/cc.c
+++ b/lib/isccc/cc.c
@@ -38,6 +38,7 @@

 #include <isc/assertions.h>
 #include <isc/hmac.h>
+#include <isc/parseint.h>
 #include <isc/result.h>
 #include <isc/safe.h>
 #include <isc/symtab.h>
@@ -881,14 +882,15 @@ isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) {
 isc_result_t
 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key, uint32_t *uintp) {
 	isccc_sexpr_t *kv, *v;
+	uint32_t value;

 	kv = isccc_alist_assq(alist, key);
 	if (kv != NULL) {
 		v = ISCCC_SEXPR_CDR(kv);
 		if (isccc_sexpr_binaryp(v)) {
-			SET_IF_NOT_NULL(uintp, (uint32_t)strtoul(
-						       isccc_sexpr_tostring(v),
-						       NULL, 10));
+			RETERR(isc_parse_uint32(&value, isccc_sexpr_tostring(v),
+						10));
+			SET_IF_NOT_NULL(uintp, value);
 			return ISC_R_SUCCESS;
 		} else {
 			return ISC_R_EXISTS;