@@ -193,13 +193,47 @@ cdef class Packet:
193
193
194
194
cdef class NetfilterQueue:
195
195
""" Handle a single numbered queue."""
196
- def __cinit__ (self , *args , **kwargs ):
197
- cdef u_int16_t af # Address family
198
- af = kwargs.get(" af" , PF_INET)
196
+ def __cinit__ (self , *, u_int16_t af = PF_INET, int sockfd = - 1 ):
197
+ cdef nfnl_handle * nlh = NULL
198
+ try :
199
+ if sockfd >= 0 :
200
+ # This is a hack to use the given Netlink socket instead
201
+ # of the one allocated by nfq_open(). Intended use case:
202
+ # the given socket was opened in a different network
203
+ # namespace, and you want to monitor traffic in that
204
+ # namespace from this process running outside of it.
205
+ # Call socket(AF_NETLINK, SOCK_RAW, /*NETLINK_NETFILTER*/ 12)
206
+ # in the other namespace and pass that fd here (via Unix
207
+ # domain socket or similar).
208
+ nlh = nfnl_open()
209
+ if nlh == NULL :
210
+ raise OSError (errno, " Failed to open nfnetlink handle" )
211
+
212
+ # At this point nfnl_get_fd(nlh) is a new netlink socket
213
+ # and has been bound to an automatically chosen port id.
214
+ # This dup2 will close it, freeing up that address.
215
+ if dup2(sockfd, nfnl_fd(nlh)) < 0 :
216
+ raise OSError (errno, " dup2 failed" )
217
+
218
+ # Opening the netfilterqueue subsystem will rebind
219
+ # the socket, using the same portid from the old socket,
220
+ # which is hopefully now free. An alternative approach,
221
+ # theoretically more robust against concurrent binds,
222
+ # would be to autobind the new socket and write the chosen
223
+ # address to nlh->local. nlh is an opaque type so this
224
+ # would need to be done using memcpy (local starts
225
+ # 4 bytes into the structure); let's avoid that unless
226
+ # we really need it.
227
+ self .h = nfq_open_nfnl(nlh)
228
+ else :
229
+ self .h = nfq_open()
230
+ if self .h == NULL :
231
+ raise OSError (errno, " Failed to open NFQueue." )
232
+ except :
233
+ if nlh != NULL :
234
+ nfnl_close(nlh)
235
+ raise
199
236
200
- self .h = nfq_open()
201
- if self .h == NULL :
202
- raise OSError (" Failed to open NFQueue." )
203
237
nfq_unbind_pf(self .h, af) # This does NOT kick out previous queues
204
238
if nfq_bind_pf(self .h, af) < 0 :
205
239
raise OSError (" Failed to bind family %s . Are you root?" % af)
0 commit comments