78
78
79
79
#if defined(__linux__ )
80
80
# include <linux/if_packet.h>
81
+ # include <linux/filter.h>
81
82
82
83
# ifndef SO_TIMESTAMP_OLD
83
84
# define SO_TIMESTAMP_OLD SO_TIMESTAMP
@@ -969,6 +970,90 @@ static struct_t st_timeval = {
969
970
};
970
971
971
972
#if defined(__linux__ )
973
+ static bool
974
+ filter_to_c (void * st , uc_value_t * uv )
975
+ {
976
+ struct sock_fprog * * fpp = st ;
977
+ struct sock_fprog * fp = * fpp ;
978
+ size_t i , len ;
979
+
980
+ if (ucv_type (uv ) == UC_STRING ) {
981
+ size_t len = ucv_string_length (uv );
982
+
983
+ if (len == 0 || (len % sizeof (struct sock_filter )) != 0 )
984
+ err_return (EINVAL , "Filter program length not a multiple of %zu" ,
985
+ sizeof (struct sock_filter ));
986
+
987
+ fp = * fpp = xrealloc (fp , sizeof (struct sock_fprog ) + len );
988
+ fp -> filter = memcpy ((char * )fp + sizeof (struct sock_fprog ), ucv_string_get (uv ), len );
989
+
990
+ if (fp -> len == 0 )
991
+ fp -> len = len / sizeof (struct sock_filter );
992
+ }
993
+ else if (ucv_type (uv ) == UC_ARRAY ) {
994
+ /* Opcode array of array. Each sub-array is a 4 element tuple */
995
+ if (ucv_type (ucv_array_get (uv , 0 )) == UC_ARRAY ) {
996
+ len = ucv_array_length (uv );
997
+
998
+ fp = * fpp = xrealloc (fp , sizeof (struct sock_fprog )
999
+ + (len * sizeof (struct sock_filter )));
1000
+
1001
+ fp -> filter = (struct sock_filter * )((char * )fp + sizeof (struct sock_fprog ));
1002
+
1003
+ for (i = 0 ; i < len ; i ++ ) {
1004
+ uc_value_t * op = ucv_array_get (uv , i );
1005
+
1006
+ if (ucv_type (op ) != UC_ARRAY )
1007
+ continue ;
1008
+
1009
+ fp -> filter [i ].code = ucv_to_unsigned (ucv_array_get (op , 0 ));
1010
+ fp -> filter [i ].jt = ucv_to_unsigned (ucv_array_get (op , 1 ));
1011
+ fp -> filter [i ].jf = ucv_to_unsigned (ucv_array_get (op , 2 ));
1012
+ fp -> filter [i ].k = ucv_to_unsigned (ucv_array_get (op , 3 ));
1013
+ }
1014
+ }
1015
+
1016
+ /* Flat opcode array, must be a multiple of 4 */
1017
+ else {
1018
+ len = ucv_array_length (uv );
1019
+
1020
+ if (len % 4 )
1021
+ err_return (EINVAL , "Opcode array length not a multiple of 4" );
1022
+
1023
+ len /= 4 ;
1024
+
1025
+ fp = * fpp = xrealloc (fp , sizeof (struct sock_fprog )
1026
+ + (len * sizeof (struct sock_filter )));
1027
+
1028
+ fp -> filter = (struct sock_filter * )((char * )fp + sizeof (struct sock_fprog ));
1029
+
1030
+ for (i = 0 ; i < len ; i ++ ) {
1031
+ fp -> filter [i ].code = ucv_to_unsigned (ucv_array_get (uv , i * 4 + 0 ));
1032
+ fp -> filter [i ].jt = ucv_to_unsigned (ucv_array_get (uv , i * 4 + 1 ));
1033
+ fp -> filter [i ].jf = ucv_to_unsigned (ucv_array_get (uv , i * 4 + 2 ));
1034
+ fp -> filter [i ].k = ucv_to_unsigned (ucv_array_get (uv , i * 4 + 3 ));
1035
+ }
1036
+ }
1037
+
1038
+ if (fp -> len == 0 )
1039
+ fp -> len = i ;
1040
+ }
1041
+ else {
1042
+ err_return (EINVAL , "Expecting either BPF bytecode string or array of opcodes" );
1043
+ }
1044
+
1045
+ return true;
1046
+ }
1047
+
1048
+ static struct_t st_sock_fprog = {
1049
+ .size = sizeof (struct sock_fprog ),
1050
+ .members = (member_t []){
1051
+ STRUCT_MEMBER_NP (sock_fprog , len , DT_UNSIGNED ),
1052
+ STRUCT_MEMBER_CB (filter , filter_to_c , NULL ),
1053
+ { 0 }
1054
+ }
1055
+ };
1056
+
972
1057
static struct_t st_ucred = {
973
1058
.size = sizeof (struct ucred ),
974
1059
.members = (member_t []){
@@ -1051,7 +1136,7 @@ in6_ifindex_to_uv(void *st)
1051
1136
static bool
1052
1137
in6_ifindex_to_c (void * st , uc_value_t * uv )
1053
1138
{
1054
- struct ipv6_mreq * mr = st ;
1139
+ struct ipv6_mreq * mr = * ( struct ipv6_mreq * * ) st ;
1055
1140
1056
1141
if (ucv_type (uv ) == UC_STRING ) {
1057
1142
mr -> ipv6mr_interface = if_nametoindex (ucv_string_get (uv ));
@@ -1189,7 +1274,9 @@ rcv_wscale_to_uv(void *st)
1189
1274
static bool
1190
1275
snd_wscale_to_c (void * st , uc_value_t * uv )
1191
1276
{
1192
- ((struct tcp_info * )st )-> tcpi_snd_wscale = ucv_to_unsigned (uv );
1277
+ struct tcp_info * ti = * (struct tcp_info * * )st ;
1278
+
1279
+ ti -> tcpi_snd_wscale = ucv_to_unsigned (uv );
1193
1280
1194
1281
if (errno )
1195
1282
err_return (errno , "Unable to convert field snd_wscale to unsigned" );
@@ -1200,7 +1287,9 @@ snd_wscale_to_c(void *st, uc_value_t *uv)
1200
1287
static bool
1201
1288
rcv_wscale_to_c (void * st , uc_value_t * uv )
1202
1289
{
1203
- ((struct tcp_info * )st )-> tcpi_rcv_wscale = ucv_to_unsigned (uv );
1290
+ struct tcp_info * ti = * (struct tcp_info * * )st ;
1291
+
1292
+ ti -> tcpi_rcv_wscale = ucv_to_unsigned (uv );
1204
1293
1205
1294
if (errno )
1206
1295
err_return (errno , "Unable to convert field rcv_wscale to unsigned" );
@@ -1314,7 +1403,7 @@ mr_ifindex_to_uv(void *st)
1314
1403
static bool
1315
1404
mr_ifindex_to_c (void * st , uc_value_t * uv )
1316
1405
{
1317
- struct packet_mreq * mr = st ;
1406
+ struct packet_mreq * mr = * ( struct packet_mreq * * ) st ;
1318
1407
1319
1408
if (ucv_type (uv ) == UC_STRING ) {
1320
1409
mr -> mr_ifindex = if_nametoindex (ucv_string_get (uv ));
@@ -1344,7 +1433,7 @@ mr_address_to_uv(void *st)
1344
1433
static bool
1345
1434
mr_address_to_c (void * st , uc_value_t * uv )
1346
1435
{
1347
- struct packet_mreq * mr = st ;
1436
+ struct packet_mreq * mr = * ( struct packet_mreq * * ) st ;
1348
1437
size_t len ;
1349
1438
1350
1439
if (!uv_to_hwaddr (uv , mr -> mr_address , & len ))
@@ -1507,7 +1596,7 @@ static sockopt_t sockopts[] = {
1507
1596
{ SOL_SOCKET , SO_TIMESTAMP , SV_BOOL },
1508
1597
{ SOL_SOCKET , SO_TYPE , SV_INT },
1509
1598
#if defined(__linux__ )
1510
- { SOL_SOCKET , SO_ATTACH_FILTER , SV_STRING },
1599
+ { SOL_SOCKET , SO_ATTACH_FILTER , & st_sock_fprog },
1511
1600
{ SOL_SOCKET , SO_ATTACH_BPF , SV_INT },
1512
1601
{ SOL_SOCKET , SO_ATTACH_REUSEPORT_CBPF , SV_STRING },
1513
1602
{ SOL_SOCKET , SO_ATTACH_REUSEPORT_EBPF , SV_INT },
@@ -1792,7 +1881,7 @@ uv_to_struct(uc_value_t *uv, struct_t *spec)
1792
1881
break ;
1793
1882
1794
1883
case DT_CALLBACK :
1795
- if (m -> u1 .to_c && !m -> u1 .to_c (st , fv )) {
1884
+ if (m -> u1 .to_c && !m -> u1 .to_c (& st , fv )) {
1796
1885
free (st );
1797
1886
return NULL ;
1798
1887
}
0 commit comments