proxy: avoid always dropping the same packet
diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c
index 5d5a02a..47d72b0 100644
--- a/programs/test/udp_proxy.c
+++ b/programs/test/udp_proxy.c
@@ -351,10 +351,49 @@
memset( &prev, 0, sizeof( packet ) );
}
+/*
+ * Avoid dropping or delaying a packet that was already dropped twice: this
+ * only results in uninteresting timeouts. We can't rely on type to identify
+ * packets, since during renegotiation they're all encrypted. So, rely on
+ * size mod 2048 (which is usually just size).
+ */
+static unsigned char dropped[2048] = { 0 };
+#define DROP_MAX 2
+
+/*
+ * OpenSSL groups packets in a datagram the first time it sends them, but not
+ * when it resends them. Count every record as seen the first time.
+ */
+void update_dropped( const packet *p )
+{
+ size_t id = p->len % sizeof( dropped );
+
+ ++dropped[id];
+
+ const unsigned char *end = p->buf + p->len;
+ const unsigned char *cur = p->buf;
+ size_t len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
+
+ /* Avoid counting single record twice */
+ if( len == p->len )
+ return;
+
+ while( cur < end )
+ {
+ size_t len = ( ( cur[11] << 8 ) | cur[12] ) + 13;
+
+ id = len % sizeof( dropped );
+ ++dropped[id];
+
+ cur += len;
+ }
+}
+
int handle_message( const char *way, int dst, int src )
{
int ret;
packet cur;
+ size_t id;
/* receive packet */
if( ( ret = net_recv( &src, cur.buf, sizeof( cur.buf ) ) ) <= 0 )
@@ -369,6 +408,8 @@
cur.dst = dst;
print_packet( &cur, NULL );
+ id = cur.len % sizeof( dropped );
+
/* do we want to drop, delay, or forward it? */
if( ( opt.mtu != 0 &&
cur.len > (unsigned) opt.mtu ) ||
@@ -376,9 +417,10 @@
strcmp( cur.type, "ApplicationData" ) != 0 &&
! ( opt.protect_hvr &&
strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
+ dropped[id] < DROP_MAX &&
rand() % opt.drop == 0 ) )
{
- ; /* Nothing to do */
+ update_dropped( &cur );
}
else if( ( opt.delay_ccs == 1 &&
strcmp( cur.type, "ChangeCipherSpec" ) == 0 ) ||
@@ -387,6 +429,7 @@
! ( opt.protect_hvr &&
strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
prev.dst == 0 &&
+ dropped[id] < DROP_MAX &&
rand() % opt.delay == 0 ) )
{
memcpy( &prev, &cur, sizeof( packet ) );
@@ -526,6 +569,7 @@
if( FD_ISSET( listen_fd, &read_fds ) )
{
clear_pending();
+ memset( dropped, 0, sizeof( dropped ) );
goto accept;
}