@@ -124,8 +124,26 @@ static int net_sock_opt_index_for(int level, int optname)
124124 }
125125 if (level == LINUX_IPPROTO_IPV6 && optname == LINUX_IPV6_V6ONLY )
126126 return SOCK_OPT_IPV6_V6ONLY ;
127- if (level == LINUX_IPPROTO_IP && optname == LINUX_IP_MTU_DISCOVER )
128- return SOCK_OPT_IP_MTU_DISCOVER ;
127+ if (level == LINUX_IPPROTO_IP ) {
128+ switch (optname ) {
129+ case LINUX_IP_TOS :
130+ return SOCK_OPT_IP_TOS ;
131+ case LINUX_IP_TTL :
132+ return SOCK_OPT_IP_TTL ;
133+ case LINUX_IP_HDRINCL :
134+ return SOCK_OPT_IP_HDRINCL ;
135+ case LINUX_IP_PKTINFO :
136+ return SOCK_OPT_IP_PKTINFO ;
137+ case LINUX_IP_RECVTTL :
138+ return SOCK_OPT_IP_RECVTTL ;
139+ case LINUX_IP_RECVTOS :
140+ return SOCK_OPT_IP_RECVTOS ;
141+ case LINUX_IP_MTU_DISCOVER :
142+ return SOCK_OPT_IP_MTU_DISCOVER ;
143+ default :
144+ return -1 ;
145+ }
146+ }
129147 return -1 ;
130148}
131149
@@ -140,6 +158,34 @@ int net_socket_cached_int_get(int guest_fd, int level, int optname, int *value)
140158 return net_sock_cache_get (guest_fd , idx , value );
141159}
142160
161+ int net_socket_cached_int_get_if_generation (int guest_fd ,
162+ uint64_t generation ,
163+ int level ,
164+ int optname ,
165+ int * value )
166+ {
167+ if (level == LINUX_SOL_SOCKET && optname == LINUX_SO_ERROR )
168+ return 0 ;
169+
170+ int idx = net_sock_opt_index_for (level , optname );
171+ if (idx < 0 || !RANGE_CHECK (guest_fd , 0 , FD_TABLE_SIZE ) || !value )
172+ return 0 ;
173+
174+ if (thread_is_single_active ()) {
175+ fd_entry_t * entry = & fd_table [guest_fd ];
176+ if (entry -> type == FD_SOCKET && entry -> generation == generation )
177+ return sock_opt_get (entry , idx , value );
178+ return 0 ;
179+ }
180+
181+ pthread_mutex_lock (& fd_lock );
182+ fd_entry_t * entry = & fd_table [guest_fd ];
183+ bool ok = entry -> type == FD_SOCKET && entry -> generation == generation &&
184+ sock_opt_get (entry , idx , value );
185+ pthread_mutex_unlock (& fd_lock );
186+ return ok ;
187+ }
188+
143189void net_socket_cached_int_set (int guest_fd , int level , int optname , int value )
144190{
145191 if (level == LINUX_SOL_SOCKET && optname == LINUX_SO_ERROR )
@@ -155,7 +201,7 @@ void net_socket_cache_init_defaults(int guest_fd, int domain, int real_type)
155201 static const int zero_opts [] = {
156202 SOCK_OPT_KEEPALIVE , SOCK_OPT_REUSEADDR , SOCK_OPT_ACCEPTCONN ,
157203 SOCK_OPT_REUSEPORT , SOCK_OPT_BROADCAST , SOCK_OPT_DONTROUTE ,
158- SOCK_OPT_OOBINLINE ,
204+ SOCK_OPT_OOBINLINE , SOCK_OPT_PASSCRED ,
159205 };
160206
161207 net_socket_cache_set_many_zero (guest_fd , zero_opts , ARRAY_SIZE (zero_opts ));
@@ -168,12 +214,19 @@ void net_socket_cache_init_defaults(int guest_fd, int domain, int real_type)
168214 net_socket_cache_set_index (guest_fd , SOCK_OPT_IPV6_V6ONLY , 0 );
169215}
170216
171- void net_socket_cache_init_accept (int guest_fd )
217+ void net_socket_cache_init_accept (int guest_fd , int inherit_passcred )
172218{
173219 static const int zero_opts [] = {
174220 SOCK_OPT_ACCEPTCONN , SOCK_OPT_REUSEPORT , SOCK_OPT_BROADCAST ,
175221 SOCK_OPT_DONTROUTE , SOCK_OPT_OOBINLINE ,
176222 };
177223
178224 net_socket_cache_set_many_zero (guest_fd , zero_opts , ARRAY_SIZE (zero_opts ));
225+
226+ /* AF_UNIX accept inherits SO_PASSCRED from the listener. For local
227+ * connects the accept path receives the value captured when the
228+ * connection was queued; otherwise it falls back to the listener value.
229+ */
230+ net_socket_cache_set_index (guest_fd , SOCK_OPT_PASSCRED ,
231+ inherit_passcred ? 1 : 0 );
179232}
0 commit comments