From the man page for dup (on FreeBSD):
The object referenced by the descriptor does not distinguish between oldd
and newd in any way. Thus if newd and oldd are duplicate references to
an open file, read(2), write(2) and lseek(2) calls all move a single
pointer into the file, and append mode, non-blocking I/O and asynchronous
I/O options are shared between the references. If a separate pointer
into the file is desired, a different object reference to the file must
be obtained by issuing an additional open(2) system call. The close-on-
exec flag on the new file descriptor is unset.
(Emphasis mine)
Look into tell + seek instead of duping.