1# This file is part of Scapy
2# See http://www.secdev.org/projects/scapy for more information
3# Copyright (C) Lucas Preston <lucas.preston@infinite.io>
4# This program is published under a GPLv2 license
5
6# scapy.contrib.description = Network File System (NFS) v3
7# scapy.contrib.status = loads
8
9from scapy.contrib.oncrpc import RPC, RPC_Call, Object_Name
10from binascii import unhexlify
11from scapy.packet import Packet, bind_layers
12from scapy.fields import IntField, IntEnumField, FieldListField, LongField, \
13    XIntField, XLongField, ConditionalField, PacketListField, StrLenField, \
14    PacketField
15from scapy.modules.six import integer_types
16
17nfsstat3 = {
18    0: 'NFS3_OK',
19    1: 'NFS3ERR_PERM',
20    2: 'NFS3ERR_NOENT',
21    5: 'NFS3ERR_IO',
22    6: 'NFS3ERR_NXIO',
23    13: 'NFS3ERR_ACCES',
24    17: 'NFS3ERR_EXIST',
25    18: 'NFS3ERR_XDEV',
26    19: 'NFS3ERR_NODEV',
27    20: 'NFS3ERR_NOTDIR',
28    21: 'NFS3ERR_ISDIR',
29    22: 'NFS3ERR_INVAL',
30    27: 'NFS3ERR_FBIG',
31    28: 'NFS3ERR_NOSPC',
32    30: 'NFS3ERR_ROFS',
33    31: 'NFS3ERR_MLINK',
34    63: 'NFS3ERR_NAMETOOLONG',
35    66: 'NFS3ERR_NOTEMPTY',
36    69: 'NFS3ERR_DQUOT',
37    70: 'NFS3ERR_STALE',
38    71: 'NFS3ERR_REMOTE',
39    10001: 'NFS3ERR_BADHANDLE',
40    10002: 'NFS3ERR_NOT_SYNC',
41    10003: 'NFS3ERR_BAD_COOKIE',
42    10004: 'NFS3ERR_NOTSUPP',
43    10005: 'NFS3ERR_TOOSMALL',
44    10006: 'NFS3ERR_SERVERFAULT',
45    10007: 'NFS3ERR_BADTYPE',
46    10008: 'NFS3ERR_JUKEBOX'
47}
48
49ftype3 = {
50    1: 'NF3REG',
51    2: 'NF3DIR',
52    3: 'NF3BLK',
53    4: 'NF3CHR',
54    5: 'NF3LNK',
55    6: 'NF3SOCK',
56    7: 'NF3FIFO'
57}
58
59
60def loct(x):
61    if isinstance(x, integer_types):
62        return oct(x)
63    if isinstance(x, tuple):
64        return "(%s)" % ", ".join(map(loct, x))
65    if isinstance(x, list):
66        return "[%s]" % ", ".join(map(loct, x))
67    return x
68
69
70class OIntField(IntField):
71    """IntField child with octal representation"""
72    def i2repr(self, pkt, x):
73        return loct(self.i2h(pkt, x))
74
75
76class Fattr3(Packet):
77    name = 'File Attributes'
78    fields_desc = [
79        IntEnumField('type', 0, ftype3),
80        OIntField('mode', 0),
81        IntField('nlink', 0),
82        IntField('uid', 0),
83        IntField('gid', 0),
84        LongField('size', 0),
85        LongField('used', 0),
86        FieldListField(
87            'rdev', [0, 0], IntField('', None), count_from=lambda x: 2
88        ),
89        XLongField('fsid', 0),
90        XLongField('fileid', 0),
91        IntField('atime_s', 0),
92        IntField('atime_ns', 0),
93        IntField('mtime_s', 0),
94        IntField('mtime_ns', 0),
95        IntField('ctime_s', 0),
96        IntField('ctime_ns', 0)
97    ]
98
99    def extract_padding(self, s):
100        return '', s
101
102
103class File_Object(Packet):
104    name = 'File Object'
105    fields_desc = [
106        IntField('length', 0),
107        StrLenField('fh', b'', length_from=lambda pkt: pkt.length),
108        StrLenField('fill', b'', length_from=lambda pkt: (4 - pkt.length) % 4)
109    ]
110
111    def set(self, new_filehandle, length=None, fill=None):
112        # convert filehandle to bytes if it was passed as a string
113        if new_filehandle.isalnum():
114            new_filehandle = unhexlify(new_filehandle)
115
116        if length is None:
117            length = len(new_filehandle)
118        if fill is None:
119            fill = b'\x00' * ((4 - length) % 4)
120
121        self.length = length
122        self.fh = new_filehandle
123        self.fill = fill
124
125    def extract_padding(self, s):
126        return '', s
127
128
129class WCC_Attr(Packet):
130    name = 'File Attributes'
131    fields_desc = [
132        LongField('size', 0),
133        IntField('mtime_s', 0),
134        IntField('mtime_ns', 0),
135        IntField('ctime_s', 0),
136        IntField('ctime_ns', 0)
137    ]
138
139    def extract_padding(self, s):
140        return '', s
141
142
143class File_From_Dir_Plus(Packet):
144    name = 'File'
145    fields_desc = [
146        LongField('fileid', 0),
147        PacketField('filename', Object_Name(), Object_Name),
148        LongField('cookie', 0),
149        IntField('attributes_follow', 0),
150        ConditionalField(
151            PacketField('attributes', Fattr3(), Fattr3),
152            lambda pkt: pkt.attributes_follow == 1
153        ),
154        IntField('handle_follows', 0),
155        ConditionalField(
156            PacketField('filehandle', File_Object(), File_Object),
157            lambda pkt: pkt.handle_follows == 1
158        ),
159        IntField('value_follows', 0)
160    ]
161
162    def extract_padding(self, s):
163        return '', s
164
165
166class File_From_Dir(Packet):
167    name = 'File'
168    fields_desc = [
169        LongField('fileid', 0),
170        PacketField('filename', Object_Name(), Object_Name),
171        LongField('cookie', 0),
172        IntField('value_follows', 0)
173    ]
174
175    def extract_padding(self, s):
176        return '', s
177
178
179attrs_enum = {0: 'DONT SET', 1: 'SET'}
180times_enum = {0: 'DONT CHANGE', 1: 'SERVER TIME', 2: 'CLIENT TIME'}
181
182
183class Sattr3(Packet):
184    name = 'Setattr3'
185    fields_desc = [
186        IntEnumField('set_mode', 0, attrs_enum),
187        ConditionalField(OIntField('mode', 0), lambda pkt: pkt.set_mode == 1),
188        IntEnumField('set_uid', 0, attrs_enum),
189        ConditionalField(IntField('uid', 0), lambda pkt: pkt.set_uid == 1),
190        IntEnumField('set_gid', 0, attrs_enum),
191        ConditionalField(IntField('gid', 0), lambda pkt: pkt.set_gid == 1),
192        IntEnumField('set_size', 0, attrs_enum),
193        ConditionalField(LongField('size', 0), lambda pkt: pkt.set_size == 1),
194        IntEnumField('set_atime', 0, times_enum),
195        ConditionalField(
196            IntField('atime_s', 0), lambda pkt: pkt.set_atime == 2
197        ),
198        ConditionalField(
199            IntField('atime_ns', 0), lambda pkt: pkt.set_atime == 2
200        ),
201        IntEnumField('set_mtime', 0, times_enum),
202        ConditionalField(
203            IntField('mtime_s', 0), lambda pkt: pkt.set_mtime == 2
204        ),
205        ConditionalField(
206            IntField('mtime_ns', 0), lambda pkt: pkt.set_mtime == 2
207        )
208    ]
209
210    def extract_padding(self, s):
211        return '', s
212
213
214class GETATTR_Call(Packet):
215    name = 'GETATTR Call'
216    fields_desc = [
217        PacketField('filehandle', File_Object(), File_Object)
218    ]
219
220
221class GETATTR_Reply(Packet):
222    name = 'GETATTR Reply'
223    fields_desc = [
224        IntEnumField('status', 0, nfsstat3),
225        ConditionalField(
226            PacketField('attributes', Fattr3(), Fattr3),
227            lambda pkt: pkt.status == 0
228        )
229    ]
230
231    def extract_padding(self, s):
232        return '', None
233
234
235bind_layers(RPC, GETATTR_Call, mtype=0)
236bind_layers(
237    RPC_Call, GETATTR_Call, program=100003, pversion=3, procedure=1
238)
239bind_layers(RPC, GETATTR_Reply, mtype=1)
240
241
242class LOOKUP_Call(Packet):
243    name = 'LOOKUP Call'
244    fields_desc = [
245        PacketField('dir', File_Object(), File_Object),
246        PacketField('filename', Object_Name(), Object_Name)
247    ]
248
249
250class LOOKUP_Reply(Packet):
251    name = 'LOOKUP Reply'
252    fields_desc = [
253        IntEnumField('status', 0, nfsstat3),
254        ConditionalField(
255            PacketField('filehandle', File_Object(), File_Object),
256            lambda pkt: pkt.status == 0
257        ),
258        ConditionalField(IntField('af_file', 0), lambda pkt: pkt.status == 0),
259        ConditionalField(
260            PacketField('file_attributes', Fattr3(), Fattr3),
261            lambda pkt: pkt.status == 0 and pkt.af_file == 1
262        ),
263        IntField('af_dir', 0),
264        ConditionalField(
265            PacketField('dir_attributes', Fattr3(), Fattr3),
266            lambda pkt: pkt.af_dir == 1
267        )
268    ]
269
270
271bind_layers(RPC, LOOKUP_Call, mtype=0)
272bind_layers(RPC, LOOKUP_Reply, mtype=1)
273bind_layers(RPC_Call, LOOKUP_Call, program=100003, pversion=3, procedure=3)
274
275
276class NULL_Call(Packet):
277    name = 'NFS NULL Call'
278    fields_desc = []
279
280
281class NULL_Reply(Packet):
282    name = 'NFS NULL Reply'
283    fields_desc = []
284
285
286bind_layers(RPC, NULL_Call, mtype=0)
287bind_layers(RPC, NULL_Reply, mtype=1)
288bind_layers(RPC_Call, NULL_Call, program=100003, pversion=3, procedure=0)
289
290
291class FSINFO_Call(Packet):
292    name = 'FSINFO Call'
293    fields_desc = [
294        PacketField('filehandle', File_Object(), File_Object)
295    ]
296
297
298class FSINFO_Reply(Packet):
299    name = 'FSINFO Reply'
300    fields_desc = [
301        IntEnumField('status', 0, nfsstat3),
302        IntField('attributes_follow', 0),
303        ConditionalField(
304            PacketField('attributes', Fattr3(), Fattr3),
305            lambda pkt: pkt.attributes_follow == 1
306        ),
307        ConditionalField(IntField('rtmax', 0), lambda pkt: pkt.status == 0),
308        ConditionalField(IntField('rtpref', 0), lambda pkt: pkt.status == 0),
309        ConditionalField(IntField('rtmult', 0), lambda pkt: pkt.status == 0),
310        ConditionalField(IntField('wtmax', 0), lambda pkt: pkt.status == 0),
311        ConditionalField(IntField('wtpref', 0), lambda pkt: pkt.status == 0),
312        ConditionalField(IntField('wtmult', 0), lambda pkt: pkt.status == 0),
313        ConditionalField(IntField('dtpref', 0), lambda pkt: pkt.status == 0),
314        ConditionalField(
315            LongField('maxfilesize', 0), lambda pkt: pkt.status == 0
316        ),
317        ConditionalField(
318            IntField('timedelta_s', 0), lambda pkt: pkt.status == 0
319        ),
320        ConditionalField(
321            IntField('timedelta_ns', 0), lambda pkt: pkt.status == 0
322        ),
323        ConditionalField(
324            XIntField('properties', 0), lambda pkt: pkt.status == 0
325        ),
326    ]
327
328
329bind_layers(RPC, FSINFO_Call, mtype=0)
330bind_layers(RPC, FSINFO_Reply, mtype=1)
331bind_layers(
332    RPC_Call, FSINFO_Call, program=100003, pversion=3, procedure=19
333)
334
335
336class PATHCONF_Call(Packet):
337    name = 'PATHCONF Call'
338    fields_desc = [
339        PacketField('filehandle', File_Object(), File_Object)
340    ]
341
342
343class PATHCONF_Reply(Packet):
344    name = 'PATHCONF Reply'
345    fields_desc = [
346        IntEnumField('status', 0, nfsstat3),
347        IntField('attributes_follow', 0),
348        ConditionalField(
349            PacketField('attributes', Fattr3(), Fattr3),
350            lambda pkt: pkt.attributes_follow == 1
351        ),
352        ConditionalField(IntField('linkmax', 0), lambda pkt: pkt.status == 0),
353        ConditionalField(IntField('name_max', 0), lambda pkt: pkt.status == 0),
354        ConditionalField(
355            IntEnumField('no_trunc', 0, {0: 'NO', 1: 'YES'}),
356            lambda pkt: pkt.status == 0
357        ),
358        ConditionalField(
359            IntEnumField('chown_restricted', 0, {0: 'NO', 1: 'YES'}),
360            lambda pkt: pkt.status == 0
361        ),
362        ConditionalField(
363            IntEnumField('case_insensitive', 0, {0: 'NO', 1: 'YES'}),
364            lambda pkt: pkt.status == 0
365        ),
366        ConditionalField(
367            IntEnumField('case_preserving', 0, {0: 'NO', 1: 'YES'}),
368            lambda pkt: pkt.status == 0
369        )
370    ]
371
372
373bind_layers(RPC, PATHCONF_Call, mtype=0)
374bind_layers(RPC, PATHCONF_Reply, mtype=1)
375bind_layers(
376    RPC_Call, PATHCONF_Call, program=100003, pversion=3, procedure=20
377)
378
379access_specs = {
380    0x0001: 'READ',
381    0x0002: 'LOOKUP',
382    0x0004: 'MODIFY',
383    0x0008: 'EXTEND',
384    0x0010: 'DELETE',
385    0x0020: 'EXECUTE'
386}
387
388
389class ACCESS_Call(Packet):
390    name = 'ACCESS Call'
391    fields_desc = [
392        PacketField('filehandle', File_Object(), File_Object),
393        IntEnumField('check_access', 1, access_specs)
394    ]
395
396
397class ACCESS_Reply(Packet):
398    name = 'ACCESS Reply'
399    fields_desc = [
400        IntEnumField('status', 0, nfsstat3),
401        IntField('attributes_follow', 0),
402        ConditionalField(
403            PacketField('attributes', Fattr3(), Fattr3),
404            lambda pkt: pkt.attributes_follow == 1
405        ),
406        ConditionalField(
407            XIntField('access_rights', 0), lambda pkt: pkt.status == 0
408        )
409    ]
410
411
412bind_layers(RPC, ACCESS_Call, mtype=0)
413bind_layers(RPC, ACCESS_Reply, mtype=1)
414bind_layers(RPC_Call, ACCESS_Call, program=100003, pversion=3, procedure=4)
415
416
417class READDIRPLUS_Call(Packet):
418    name = 'READDIRPLUS Call'
419    fields_desc = [
420        PacketField('filehandle', File_Object(), File_Object),
421        LongField('cookie', 0),
422        LongField('verifier', 0),
423        IntField('dircount', 512),
424        IntField('maxcount', 4096)
425    ]
426
427
428class READDIRPLUS_Reply(Packet):
429    name = 'READDIRPLUS Reply'
430    fields_desc = [
431        IntEnumField('status', 0, nfsstat3),
432        IntField('attributes_follow', 0),
433        ConditionalField(
434            PacketField('attributes', Fattr3(), Fattr3),
435            lambda pkt: pkt.attributes_follow == 1
436        ),
437        ConditionalField(
438            LongField('verifier', 0), lambda pkt: pkt.status == 0
439        ),
440        ConditionalField(
441            IntField('value_follows', 0), lambda pkt: pkt.status == 0
442        ),
443        ConditionalField(
444            PacketListField(
445                'files', None, File_From_Dir_Plus,
446                next_cls_cb=lambda pkt, lst, cur, remain:
447                File_From_Dir_Plus if pkt.value_follows == 1 and
448                (len(lst) == 0 or cur.value_follows == 1) and
449                len(remain) > 4 else None
450            ),
451            lambda pkt: pkt.status == 0
452        ),
453        ConditionalField(IntField('eof', 0), lambda pkt: pkt.status == 0)
454    ]
455
456    def extract_padding(self, s):
457        return '', s
458
459
460bind_layers(RPC, READDIRPLUS_Call, mtype=0)
461bind_layers(RPC, READDIRPLUS_Reply, mtype=1)
462bind_layers(
463    RPC_Call, READDIRPLUS_Call, program=100003, pversion=3, procedure=17
464)
465
466
467class WRITE_Call(Packet):
468    name = 'WRITE Call'
469    fields_desc = [
470        PacketField('filehandle', File_Object(), File_Object),
471        LongField('offset', 0),
472        IntField('count', 0),
473        IntEnumField('stable', 0, {0: 'UNSTABLE', 1: 'STABLE'}),
474        IntField('length', 0),
475        StrLenField('contents', b'', length_from=lambda pkt: pkt.length),
476        StrLenField('fill', b'', length_from=lambda pkt: (4 - pkt.length) % 4)
477    ]
478
479
480class WRITE_Reply(Packet):
481    name = 'WRITE Reply'
482    fields_desc = [
483        IntEnumField('status', 0, nfsstat3),
484        IntField('af_before', 0),
485        ConditionalField(
486            PacketField('attributes_before', WCC_Attr(), WCC_Attr),
487            lambda pkt: pkt.af_before == 1
488        ),
489        IntField('af_after', 0),
490        ConditionalField(
491            PacketField('attributes_after', Fattr3(), Fattr3),
492            lambda pkt: pkt.af_after == 1
493        ),
494        ConditionalField(IntField('count', 0), lambda pkt: pkt.status == 0),
495        ConditionalField(
496            IntEnumField('committed', 0, {0: 'UNSTABLE', 1: 'STABLE'}),
497            lambda pkt: pkt.status == 0
498        ),
499        ConditionalField(
500            XLongField('verifier', 0), lambda pkt: pkt.status == 0
501        )
502    ]
503
504
505bind_layers(RPC, WRITE_Call, mtype=0)
506bind_layers(RPC, WRITE_Reply, mtype=1)
507bind_layers(RPC_Call, WRITE_Call, program=100003, pversion=3, procedure=7)
508
509
510class COMMIT_Call(Packet):
511    name = 'COMMIT Call'
512    fields_desc = [
513        PacketField('filehandle', File_Object(), File_Object),
514        LongField('offset', 0),
515        IntField('count', 0)
516    ]
517
518
519class COMMIT_Reply(Packet):
520    name = 'COMMIT Reply'
521    fields_desc = [
522        IntEnumField('status', 0, nfsstat3),
523        IntField('af_before', 0),
524        ConditionalField(
525            PacketField('attributes_before', WCC_Attr(), WCC_Attr),
526            lambda pkt: pkt.af_before == 1
527        ),
528        IntField('af_after', 0),
529        ConditionalField(
530            PacketField('attributes_after', Fattr3(), Fattr3),
531            lambda pkt: pkt.af_after == 1
532        ),
533        ConditionalField(
534            XLongField('verifier', 0), lambda pkt: pkt.status == 0
535        )
536    ]
537
538
539bind_layers(RPC, COMMIT_Call, mtype=0)
540bind_layers(RPC, COMMIT_Reply, mtype=1)
541bind_layers(
542    RPC_Call, COMMIT_Call, program=100003, pversion=3, procedure=21
543)
544
545
546class SETATTR_Call(Packet):
547    name = 'SETATTR Call'
548    fields_desc = [
549        PacketField('filehandle', File_Object(), File_Object),
550        PacketField('attributes', Sattr3(), Sattr3),
551        IntField('check', 0)
552    ]
553
554
555class SETATTR_Reply(Packet):
556    name = 'SETATTR Reply'
557    fields_desc = [
558        IntEnumField('status', 0, nfsstat3),
559        IntField('af_before', 0),
560        ConditionalField(
561            PacketField('attributes_before', WCC_Attr(), WCC_Attr),
562            lambda pkt: pkt.af_before == 1
563        ),
564        IntField('af_after', 0),
565        ConditionalField(
566            PacketField('attributes_after', Fattr3(), Fattr3),
567            lambda pkt: pkt.af_after == 1
568        )
569    ]
570
571
572bind_layers(RPC, SETATTR_Call, mtype=0)
573bind_layers(RPC, SETATTR_Reply, mtype=1)
574bind_layers(
575    RPC_Call, SETATTR_Call, program=100003, pversion=3, procedure=2
576)
577
578
579class FSSTAT_Call(Packet):
580    name = 'FSSTAT Call'
581    fields_desc = [
582        PacketField('filehandle', File_Object(), File_Object)
583    ]
584
585
586class FSSTAT_Reply(Packet):
587    name = 'FSSTAT Reply'
588    fields_desc = [
589        IntEnumField('status', 0, nfsstat3),
590        IntField('attributes_follow', 0),
591        ConditionalField(
592            PacketField('attributes', Fattr3(), Fattr3),
593            lambda pkt: pkt.attributes_follow == 1
594        ),
595        ConditionalField(LongField('tbytes', 0), lambda pkt: pkt.status == 0),
596        ConditionalField(LongField('fbytes', 0), lambda pkt: pkt.status == 0),
597        ConditionalField(LongField('abytes', 0), lambda pkt: pkt.status == 0),
598        ConditionalField(LongField('tfiles', 0), lambda pkt: pkt.status == 0),
599        ConditionalField(LongField('ffiles', 0), lambda pkt: pkt.status == 0),
600        ConditionalField(LongField('afiles', 0), lambda pkt: pkt.status == 0),
601        ConditionalField(IntField('invarsec', 0), lambda pkt: pkt.status == 0)
602    ]
603
604
605bind_layers(RPC, FSSTAT_Call, mtype=0)
606bind_layers(RPC, FSSTAT_Reply, mtype=1)
607bind_layers(
608    RPC_Call, FSSTAT_Call, program=100003, pversion=3, procedure=18
609)
610
611
612class CREATE_Call(Packet):
613    name = 'CREATE Call'
614    fields_desc = [
615        PacketField('dir', File_Object(), File_Object),
616        PacketField('filename', Object_Name(), Object_Name),
617        IntEnumField('create_mode', None, {0: 'UNCHECKED',
618                                           1: 'GUARDED',
619                                           2: 'EXCLUSIVE'}),
620        ConditionalField(
621            PacketField('attributes', Sattr3(), Sattr3),
622            lambda pkt: pkt.create_mode != 2
623        ),
624        ConditionalField(
625            XLongField('verifier', 0), lambda pkt: pkt.create_mode == 2
626        )
627    ]
628
629
630class CREATE_Reply(Packet):
631    name = 'CREATE Reply'
632    fields_desc = [
633        IntEnumField('status', 0, nfsstat3),
634        ConditionalField(
635            IntField('handle_follows', 0), lambda pkt: pkt.status == 0
636        ),
637        ConditionalField(
638            PacketField('filehandle', File_Object(), File_Object),
639            lambda pkt: pkt.status == 0 and pkt.handle_follows == 1
640        ),
641        ConditionalField(
642            IntField('attributes_follow', 0), lambda pkt: pkt.status == 0
643        ),
644        ConditionalField(
645            PacketField('attributes', Fattr3(), Fattr3),
646            lambda pkt: pkt.status == 0 and pkt.attributes_follow == 1
647        ),
648        IntField('af_before', 0),
649        ConditionalField(
650            PacketField('dir_attributes_before', WCC_Attr(), WCC_Attr),
651            lambda pkt: pkt.af_before == 1
652        ),
653        IntField('af_after', 0),
654        ConditionalField(
655            PacketField('dir_attributes_after', Fattr3(), Fattr3),
656            lambda pkt: pkt.af_after == 1
657        )
658    ]
659
660
661bind_layers(RPC, CREATE_Call, mtype=0)
662bind_layers(RPC, CREATE_Reply, mtype=1)
663bind_layers(RPC_Call, CREATE_Call, program=100003, pversion=3, procedure=8)
664
665
666class REMOVE_Call(Packet):
667    name = 'REMOVE Call'
668    fields_desc = [
669        PacketField('dir', File_Object(), File_Object),
670        PacketField('filename', Object_Name(), Object_Name)
671    ]
672
673
674class REMOVE_Reply(Packet):
675    name = 'REMOVE Reply'
676    fields_desc = [
677        IntEnumField('status', 0, nfsstat3),
678        IntField('af_before', 0),
679        ConditionalField(
680            PacketField('attributes_before', WCC_Attr(), WCC_Attr),
681            lambda pkt: pkt.af_before == 1
682        ),
683        IntField('af_after', 0),
684        ConditionalField(
685            PacketField('attributes_after', Fattr3(), Fattr3),
686            lambda pkt: pkt.af_after == 1
687        )
688    ]
689
690
691bind_layers(RPC, REMOVE_Call, mtype=0)
692bind_layers(RPC, REMOVE_Reply, mtype=1)
693bind_layers(
694    RPC_Call, REMOVE_Call, program=100003, pversion=3, procedure=12
695)
696
697
698class READDIR_Call(Packet):
699    name = 'READDIR Call'
700    fields_desc = [
701        PacketField('filehandle', File_Object(), File_Object),
702        LongField('cookie', 0),
703        XLongField('verifier', 0),
704        IntField('count', 0)
705    ]
706
707
708class READDIR_Reply(Packet):
709    name = 'READDIR Reply'
710    fields_desc = [
711        IntEnumField('status', 0, nfsstat3),
712        IntField('attributes_follow', 0),
713        ConditionalField(
714            PacketField('attributes', Fattr3(), Fattr3),
715            lambda pkt: pkt.attributes_follow == 1
716        ),
717        ConditionalField(
718            XLongField('verifier', 0), lambda pkt: pkt.status == 0
719        ),
720        ConditionalField(
721            IntField('value_follows', 0), lambda pkt: pkt.status == 0
722        ),
723        ConditionalField(
724            PacketListField(
725                'files', None, File_From_Dir,
726                next_cls_cb=lambda pkt, lst, cur, remain:
727                File_From_Dir if pkt.value_follows == 1 and
728                (len(lst) == 0 or cur.value_follows == 1) and
729                len(remain) > 4 else None
730            ),
731            lambda pkt: pkt.status == 0),
732        ConditionalField(IntField('eof', 0), lambda pkt: pkt.status == 0)
733    ]
734
735
736bind_layers(RPC, READDIR_Call, mtype=0)
737bind_layers(RPC, READDIR_Reply, mtype=1)
738bind_layers(
739    RPC_Call, READDIR_Call, program=100003, pversion=3, procedure=16
740)
741
742
743class RENAME_Call(Packet):
744    name = 'RENAME Call'
745    fields_desc = [
746        PacketField('dir_from', File_Object(), File_Object),
747        PacketField('name_from', Object_Name(), Object_Name),
748        PacketField('dir_to', File_Object(), File_Object),
749        PacketField('name_to', Object_Name(), Object_Name),
750    ]
751
752
753class RENAME_Reply(Packet):
754    name = 'RENAME Reply'
755    fields_desc = [
756        IntEnumField('status', 0, nfsstat3),
757        IntField('af_before_f', 0),
758        ConditionalField(
759            PacketField('attributes_before_f', WCC_Attr(), WCC_Attr),
760            lambda pkt: pkt.af_before_f == 1
761        ),
762        IntField('af_after_f', 0),
763        ConditionalField(
764            PacketField('attributes_after_f', Fattr3(), Fattr3),
765            lambda pkt: pkt.af_after_f == 1
766        ),
767        IntField('af_before_t', 0),
768        ConditionalField(
769            PacketField('attributes_before_t', WCC_Attr(), WCC_Attr),
770            lambda pkt: pkt.af_before_t == 1
771        ),
772        IntField('af_after_t', 0),
773        ConditionalField(
774            PacketField('attributes_after_t', Fattr3(), Fattr3),
775            lambda pkt: pkt.af_after_t == 1
776        )
777    ]
778
779
780bind_layers(RPC, RENAME_Call, mtype=0)
781bind_layers(RPC, RENAME_Reply, mtype=1)
782bind_layers(
783    RPC_Call, RENAME_Call, program=100003, pversion=3, procedure=14
784)
785
786
787class LINK_Call(Packet):
788    name = 'LINK Call'
789    fields_desc = [
790        PacketField('filehandle', File_Object(), File_Object),
791        PacketField('link_dir', File_Object(), File_Object),
792        PacketField('link_name', Object_Name(), Object_Name)
793    ]
794
795
796class LINK_Reply(Packet):
797    name = 'LINK Reply'
798    fields_desc = [
799        IntEnumField('status', 0, nfsstat3),
800        IntField('af_file', 0),
801        ConditionalField(
802            PacketField('file_attributes', Fattr3(), Fattr3),
803            lambda pkt: pkt.af_file == 1
804        ),
805        IntField('af_link_before', 0),
806        ConditionalField(
807            PacketField('link_attributes_before', WCC_Attr(), WCC_Attr),
808            lambda pkt: pkt.af_link_before == 1
809        ),
810        IntField('af_link_after', 0),
811        ConditionalField(
812            PacketField('link_attributes_after', Fattr3(), Fattr3),
813            lambda pkt: pkt.af_link_after == 1
814        )
815    ]
816
817
818bind_layers(RPC, LINK_Call, mtype=0)
819bind_layers(RPC, LINK_Reply, mtype=1)
820bind_layers(RPC_Call, LINK_Call, program=100003, pversion=3, procedure=15)
821
822
823class RMDIR_Call(Packet):
824    name = 'RMDIR Call'
825    fields_desc = [
826        PacketField('dir', File_Object(), File_Object),
827        PacketField('filename', Object_Name(), Object_Name),
828    ]
829
830
831class RMDIR_Reply(Packet):
832    name = 'RMDIR Reply'
833    fields_desc = [
834        IntEnumField('status', 0, nfsstat3),
835        IntField('af_before', 0),
836        ConditionalField(
837            PacketField('attributes_before', WCC_Attr(), WCC_Attr),
838            lambda pkt: pkt.af_before == 1
839        ),
840        IntField('af_after', 0),
841        ConditionalField(
842            PacketField('attributes_after', Fattr3(), Fattr3),
843            lambda pkt: pkt.af_after == 1
844        )
845    ]
846
847
848bind_layers(RPC, RMDIR_Call, mtype=0)
849bind_layers(RPC, RMDIR_Reply, mtype=1)
850bind_layers(RPC_Call, RMDIR_Call, program=100003, pversion=3, procedure=13)
851
852
853class READLINK_Call(Packet):
854    name = 'READLINK Call'
855    fields_desc = [
856        PacketField('filehandle', File_Object(), File_Object)
857    ]
858
859
860class READLINK_Reply(Packet):
861    name = 'READLINK Reply'
862    fields_desc = [
863        IntEnumField('status', 0, nfsstat3),
864        IntField('attributes_follow', 0),
865        ConditionalField(
866            PacketField('attributes', Fattr3(), Fattr3),
867            lambda pkt: pkt.attributes_follow == 1
868        ),
869        ConditionalField(
870            PacketField('filename', Object_Name(), Object_Name),
871            lambda pkt: pkt.status == 0
872        )
873    ]
874
875
876bind_layers(RPC, READLINK_Call, mtype=0)
877bind_layers(RPC, READLINK_Reply, mtype=1)
878bind_layers(
879    RPC_Call, READLINK_Call, program=100003, pversion=3, procedure=5
880)
881
882
883class READ_Call(Packet):
884    name = 'READ Call'
885    fields_desc = [
886        PacketField('filehandle', File_Object(), File_Object),
887        LongField('offset', 0),
888        IntField('count', 0)
889    ]
890
891
892class READ_Reply(Packet):
893    name = 'READ Reply'
894    fields_desc = [
895        IntEnumField('status', 0, nfsstat3),
896        IntField('attributes_follow', 0),
897        ConditionalField(
898            PacketField('attributes', Fattr3(), Fattr3),
899            lambda pkt: pkt.attributes_follow == 1
900        ),
901        ConditionalField(IntField('count', 0), lambda pkt: pkt.status == 0),
902        ConditionalField(IntField('eof', 0), lambda pkt: pkt.status == 0),
903        ConditionalField(
904            IntField('data_length', 0), lambda pkt: pkt.status == 0
905        ),
906        ConditionalField(
907            StrLenField('data', b'', length_from=lambda pkt: pkt.data_length),
908            lambda pkt: pkt.status == 0
909        ),
910        ConditionalField(
911            StrLenField(
912                'fill', b'', length_from=lambda pkt: (4 - pkt.data_length) % 4
913            ),
914            lambda pkt: pkt.status == 0
915        )
916    ]
917
918
919bind_layers(RPC, READ_Call, mtype=0)
920bind_layers(RPC, READ_Reply, mtype=1)
921bind_layers(RPC_Call, READ_Call, program=100003, pversion=3, procedure=6)
922
923
924class MKDIR_Call(Packet):
925    name = 'MKDIR Call'
926    fields_desc = [
927        PacketField('dir', File_Object(), File_Object),
928        PacketField('dir_name', Object_Name(), Object_Name),
929        PacketField('attributes', Sattr3(), Sattr3)
930    ]
931
932
933class MKDIR_Reply(Packet):
934    name = 'MKDIR Reply'
935    fields_desc = [
936        IntEnumField('status', 0, nfsstat3),
937        ConditionalField(
938            IntField('handle_follows', 0), lambda pkt: pkt.status == 0
939        ),
940        ConditionalField(
941            PacketField('filehandle', File_Object(), File_Object),
942            lambda pkt: pkt.status == 0 and pkt.handle_follows == 1
943        ),
944        ConditionalField(
945            IntField('attributes_follow', 0), lambda pkt: pkt.status == 0
946        ),
947        ConditionalField(
948            PacketField('attributes', Fattr3(), Fattr3),
949            lambda pkt: pkt.status == 0 and pkt.attributes_follow == 1
950        ),
951        IntField('af_before', 0),
952        ConditionalField(
953            PacketField('dir_attributes_before', WCC_Attr(), WCC_Attr),
954            lambda pkt: pkt.af_before == 1
955        ),
956        IntField('af_after', 0),
957        ConditionalField(
958            PacketField('dir_attributes_after', Fattr3(), Fattr3),
959            lambda pkt: pkt.af_after == 1
960        )
961    ]
962
963
964bind_layers(RPC, MKDIR_Call, mtype=0)
965bind_layers(RPC, MKDIR_Reply, mtype=1)
966bind_layers(RPC_Call, MKDIR_Call, program=100003, pversion=3, procedure=9)
967
968
969class SYMLINK_Call(Packet):
970    name = 'SYMLINK Call'
971    fields_desc = [
972        PacketField('dir', File_Object(), File_Object),
973        PacketField('dir_name', Object_Name(), Object_Name),
974        PacketField('attributes', Sattr3(), Sattr3),
975        PacketField('link_name', Object_Name(), Object_Name)
976    ]
977
978
979class SYMLINK_Reply(Packet):
980    name = 'SYMLINK Reply'
981    fields_desc = [
982        IntEnumField('status', 0, nfsstat3),
983        ConditionalField(
984            IntField('handle_follows', 0), lambda pkt: pkt.status == 0
985        ),
986        ConditionalField(
987            PacketField('filehandle', File_Object(), File_Object),
988            lambda pkt: pkt.status == 0 and pkt.handle_follows == 1
989        ),
990        ConditionalField(
991            IntField('attributes_follow', 0), lambda pkt: pkt.status == 0
992        ),
993        ConditionalField(
994            PacketField('attributes', Fattr3(), Fattr3),
995            lambda pkt: pkt.status == 0 and pkt.attributes_follow == 1
996        ),
997        IntField('af_before', 0),
998        ConditionalField(
999            PacketField('dir_attributes_before', WCC_Attr(), WCC_Attr),
1000            lambda pkt: pkt.af_before == 1
1001        ),
1002        IntField('af_after', 0),
1003        ConditionalField(
1004            PacketField('dir_attributes_after', Fattr3(), Fattr3),
1005            lambda pkt: pkt.af_after == 1
1006        )
1007    ]
1008
1009
1010bind_layers(RPC, SYMLINK_Call, mtype=0)
1011bind_layers(RPC, SYMLINK_Reply, mtype=1)
1012bind_layers(
1013    RPC_Call, SYMLINK_Call, program=100003, pversion=3, procedure=10
1014)
1015