diff --git a/tpws/params.h b/tpws/params.h
index 2ec3ac9..b1bfc2c 100644
--- a/tpws/params.h
+++ b/tpws/params.h
@@ -61,6 +61,7 @@ struct params_s
 	int hostlist_auto_fail_threshold, hostlist_auto_fail_time;
 	hostfail_pool *hostlist_auto_fail_counters;
 
+	bool tamper_start_n,tamper_cutoff_n;
 	unsigned int tamper_start,tamper_cutoff;
 
 	int debug;
diff --git a/tpws/tpws.c b/tpws/tpws.c
index c5a254f..a6ff607 100644
--- a/tpws/tpws.c
+++ b/tpws/tpws.c
@@ -189,8 +189,8 @@ static void exithelp(void)
 		" --unixeol\t\t\t\t; replace 0D0A to 0A\n"
 		" --tlsrec=sni\t\t\t\t; make 2 TLS records. split at SNI. don't split if SNI is not present\n"
 		" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
-		" --tamper-start=<pos>\t\t\t; start tampering only from specified outbound stream position. default is 0.\n"
-		" --tamper-cutoff=<pos>\t\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n",
+		" --tamper-start=[n]<pos>\t\t; start tampering only from specified outbound stream position. default is 0. 'n' means data block number.\n"
+		" --tamper-cutoff=[n]<pos>\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n",
 		HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT
 	);
 	exit(1);
@@ -670,10 +670,30 @@ void parse_params(int argc, char *argv[])
 			params.skip_nodelay = true;
 			break;
 		case 49: /* tamper-start */
-			params.tamper_start = atoi(optarg);
+			{
+				const char *p=optarg;
+				if (*p=='n')
+				{
+					params.tamper_start_n=true;
+					p++;
+				}
+				else
+					params.tamper_start_n=false;
+				params.tamper_start = atoi(p);
+			}
 			break;
 		case 50: /* tamper-cutoff */
-			params.tamper_cutoff = atoi(optarg);
+			{
+				const char *p=optarg;
+				if (*p=='n')
+				{
+					params.tamper_cutoff_n=true;
+					p++;
+				}
+				else
+					params.tamper_cutoff_n=false;
+				params.tamper_cutoff = atoi(p);
+			}
 			break;
 #if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__)
 		case 51: /* enable-pf */
diff --git a/tpws/tpws_conn.c b/tpws/tpws_conn.c
index aa7893e..b80b37b 100644
--- a/tpws/tpws_conn.c
+++ b/tpws/tpws_conn.c
@@ -893,6 +893,12 @@ static bool handle_proxy_mode(tproxy_conn_t *conn, struct tailhead *conn_list)
 	return false;
 }
 
+static bool in_tamper_out_range(tproxy_conn_t *conn)
+{
+	return (params.tamper_start_n ? (conn->tnrd+1) : conn->trd) >= params.tamper_start &&
+		(!params.tamper_cutoff || (params.tamper_cutoff_n ? (conn->tnrd+1) : conn->trd) < params.tamper_cutoff);
+}
+
 static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_size, size_t *segment_size, size_t *split_pos)
 {
 	*split_pos=0;
@@ -905,13 +911,16 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
 				tamper_in(&conn->partner->track,segment,segment_buffer_size,segment_size);
 			}
 		}
-		else if (conn->trd >= params.tamper_start && (!params.tamper_cutoff || conn->trd < params.tamper_cutoff))
+		else
 		{
-			DBGPRINT("tamper_out stream pos %zu. tamper range %u-%u", conn->trd, params.tamper_start, params.tamper_cutoff)
-			tamper_out(&conn->track,segment,segment_buffer_size,segment_size,split_pos);
+			bool in_range = in_tamper_out_range(conn);
+			DBGPRINT("tamper_out stream pos %" PRIu64 "(n%" PRIu64 "). tamper range %s%u-%s%u (%s)",
+				conn->trd, conn->tnrd+1,
+				params.tamper_start_n ? "n" : "" , params.tamper_start,
+				params.tamper_cutoff_n ? "n" : "" , params.tamper_cutoff,
+				in_range ? "IN RANGE" : "OUT OF RANGE")
+			if (in_range) tamper_out(&conn->track,segment,segment_buffer_size,segment_size,split_pos);
 		}
-		else
-			DBGPRINT("stream pos %zu is out of tamper range %u-%u", conn->trd, params.tamper_start, params.tamper_cutoff)
 	}
 }
 
@@ -945,14 +954,14 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
 	{
 		// throw it to a black hole
 		uint8_t waste[65070];
-		ssize_t trd=0;
+		uint64_t trd=0;
 
 		while((rd=recv(conn->fd, waste, sizeof(waste), MSG_DONTWAIT))>0 && trd<MAX_WASTE)
 		{
 			trd+=rd;
 			conn->trd+=rd;
 		}
-		DBGPRINT("wasted recv=%zd all_rd=%zd err=%d",rd,trd,errno)
+		DBGPRINT("wasted recv=%zd all_rd=%" PRIu64 " err=%d",rd,trd,errno)
 		return true;
 	}
 
@@ -966,13 +975,9 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
 	DBGPRINT("numbytes=%d",numbytes)
 	if (numbytes>0)
 	{
-		if (conn->remote)
-			VPRINT("remote leg stream pos R/W : %zu/%zu",conn->trd,conn->twr)
-		else
-			VPRINT("local leg stream pos : %zu/%zu",conn->trd,conn->twr)
+		VPRINT("%s leg stream pos : %" PRIu64 "(n%" PRIu64 ")/%" PRIu64, conn->remote ? "remote" : "local", conn->trd,conn->tnrd+1,conn->twr)
 #ifdef SPLICE_PRESENT
-		if (!params.tamper || conn->remote && conn->partner->track.bTamperInCutoff ||
-			!conn->remote && (conn->trd < params.tamper_start || params.tamper_cutoff && conn->trd >= params.tamper_cutoff))
+		if (!params.tamper || conn->remote && conn->partner->track.bTamperInCutoff || !conn->remote && !in_tamper_out_range(conn))
 		{
 			// incoming data from remote leg we splice without touching
 			// pipe is in the local leg, so its in conn->partner->splice_pipe
@@ -983,6 +988,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
 			if (rd<0 && errno==EAGAIN) rd=0;
 			if (rd>0)
 			{
+				conn->tnrd++;
 				conn->trd += rd;
 				conn->partner->wr_unsent += rd;
 				wr = splice(conn->partner->splice_pipe[0], NULL, conn->partner->fd, NULL, conn->partner->wr_unsent, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
@@ -1013,6 +1019,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
 				// tamper needs to know stream position of the block start
 				tamper(conn, buf, sizeof(buf), &bs, &split_pos);
 				// increase after tamper
+				conn->tnrd++;
 				conn->trd+=rd;
 
 				if (split_pos)
@@ -1070,7 +1077,7 @@ static bool remove_closed_connections(int efd, struct tailhead *close_list)
 
 		shutdown(conn->fd,SHUT_RDWR);
 		epoll_del(conn);
-		VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) closed, connection removed. total_read=%zu total_write=%zu event_count=%u",
+		VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) closed, connection removed. total_read=%" PRIu64 " total_write=%" PRIu64 " event_count=%u",
 			conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, conn->trd, conn->twr, conn->event_count)
 		if (conn->remote) legs_remote--; else legs_local--;
 		free_conn(conn);
diff --git a/tpws/tpws_conn.h b/tpws/tpws_conn.h
index 5575e88..e279dea 100644
--- a/tpws/tpws_conn.h
+++ b/tpws/tpws_conn.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <stdbool.h>
+#include <inttypes.h>
 #include <sys/queue.h>
 #include <time.h>
 #include "tamper.h"
@@ -67,7 +68,7 @@ struct tproxy_conn
 	bool bFlowIn,bFlowOut, bFlowInPrev,bFlowOutPrev, bPrevRdhup;
 
 	// total read,write
-	size_t trd,twr;
+	uint64_t trd,twr, tnrd;
 	// number of epoll_wait events
 	unsigned int event_count;