/* \* ctl_getitem - get the next data item from the incoming packet */ static const struct ctl_var * ctl_getitem( const struct ctl_var *var_list, char **data ) { /* [Bug 3008] First check the packet data sanity, then search \* the key. This improves the consistency of result values: If \* the result is NULL once, it will never be EOV again for this \* packet; If it's EOV, it will never be NULL again until the \* variable is found and processed in a given 'var_list'. (That \* is, a result is returned that is neither NULL nor EOV). */ static const struct ctl_var eol = { 0, EOV, NULL }; static char buf[128]; static u_long quiet_until; const struct ctl_var *v; char *cp; char *tp; /* \* Part One: Validate the packet state */ /* Delete leading commas and white space */ while (reqpt < reqend && (*reqpt == ',' || isspace((unsigned char)*reqpt))) reqpt++; if (reqpt >= reqend) return NULL; /* Scan the string in the packet until we hit comma or \* EoB. Register position of first '=' on the fly. */ for (tp = NULL, cp = reqpt; cp != reqend; ++cp) { if (*cp == '=' && tp == NULL) tp = cp; if (*cp == ',') break; } /* Process payload, if any. */ *data = NULL; if (NULL != tp) { /* eventually strip white space from argument. */ const char *plhead = tp + 1; /* skip the '=' */ const char *pltail = cp; size_t plsize; while (plhead != pltail && isspace((u_char)plhead[0])) ++plhead; while (plhead != pltail && isspace((u_char)pltail[-1])) --pltail; /* check payload size, terminate packet on overflow */ plsize = (size_t)(pltail - plhead); if (plsize >= sizeof(buf)) goto badpacket; /* copy data, NUL terminate, and set result data ptr */ memcpy(buf, plhead, plsize); buf[plsize] = '\0'; *data = buf; } else { /* no payload, current end --> current name termination */ tp = cp; } /* Part Two * \* Now we're sure that the packet data itself is sane. Scan the \* list now. Make sure a NULL listis properly treated by \* returning a synthetic End-Of-Values record. We must not \* return NULL pointers after this point, or the behaviour would \* become inconsistent if called several times with different \* variable lists after an EoV was returned. (Such a behavior \* actually caused Bug 3008.) */ if (NULL == var_list) return &eol; for (v = var_list; !(EOV & v->flags); ++v) if (!(PADDING & v->flags)) { /* Check if the var name matches the buffer. The \* name is bracketed by [reqpt..tp] andnot NUL \* terminated, and it contains no '=' char. The \* lookup value IS NUL-terminated but might \* include a '='... We have to look out for \* that! */ const char *sp1 = reqpt; const char *sp2 = v->text; /* [Bug 3412] do not compare past NUL byte in name */ while ( (sp1 != tp) && ('\0' != *sp2) && (*sp1 == *sp2)) { ++sp1; ++sp2; } if (sp1 == tp && (*sp2 == '\0' || *sp2 == '=')) break; } /* See if we have found a valid entry ornot. If found, advance \* the request pointer for the nextround; ifnot, clear the \* data pointer so we have no dangling garbage here. */ if (EOV & v->flags) *data = NULL; else reqpt = cp + (cp != reqend); return v; badpacket: /*TODO? somehow indicate this packet was bad, apart from syslog? */ numctlbadpkts++; NLOG(NLOG_SYSEVENT) if (quiet_until <= current_time) { quiet_until = current_time + 300; msyslog(LOG_WARNING, "Possible 'ntpdx' exploit from %s#%" PRIu16 " (possibly spoofed)", socktoa(rmt_addr), SRCPORT(rmt_addr)); } reqpt = reqend; /* never again for this packet! */ return NULL; } /* \* control_unspec - response to an unspecified op-code */ /*ARGSUSED*/ static void control_unspec( struct recvbuf *rbufp, int restrict_mask ) { struct peer *peer; UNUSED_ARG(rbufp); UNUSED_ARG(restrict_mask); /* \* What is an appropriate response to an unspecified op-code? \* I return no errors and no data, unless a specified association \* doesn't exist. */ if (res_associd) { peer = findpeerbyassoc(res_associd); if (NULL == peer) { ctl_error(CERR_BADASSOC); return; } rpkt.status = htons(ctlpeerstatus(peer)); } else rpkt.status = htons(ctlsysstatus()); ctl_flushpkt(0); }
b. 可以看出来这个函数第二个参数是被修改的对象,所以对data进行追踪,这里是二级指针,我们最后是因为valuep的值是0,所以导致原因是*data被赋值成0返回了。调试前valuep的值
structrecvbuf { recvbuf_t * link; /* next in list */ sockaddr_u recv_srcadr; sockaddr_u srcadr; /* where packet came from */ structnetendpt * dstadr;/* address pkt arrived on */ SOCKET fd; /* fd on which it was received */ l_fp recv_time; /* time of arrival */ void (*receiver)(struct recvbuf *); /* callback */ size_t recv_length; /* number of octets received */ union { structpktX_recv_pkt; uint8_t X_recv_buffer[RX_BUFF_SIZE]; } recv_space; #define recv_pkt recv_space.X_recv_pkt #define recv_buffer recv_space.X_recv_buffer structparsed_pktpkt;/* host-order copy of data from wire */ int used; /* reference count */ bool keyid_present; keyid_t keyid; int mac_len; #ifdef REFCLOCK bool network_packet; structpeer * recv_peer; #endif/* REFCLOCK */ };
structrecvbuf { recvbuf_t * link; /* next in list */ sockaddr_u recv_srcadr; sockaddr_u srcadr; /* where packet came from */ structnetendpt * dstadr;/* address pkt arrived on */ SOCKET fd; /* fd on which it was received */ l_fp recv_time; /* time of arrival */ void (*receiver)(struct recvbuf *); /* callback */ size_t recv_length; /* number of octets received */ union { structpktX_recv_pkt; uint8_t X_recv_buffer[RX_BUFF_SIZE]; } recv_space; #define recv_pkt recv_space.X_recv_pkt #define recv_buffer recv_space.X_recv_buffer structparsed_pktpkt;/* host-order copy of data from wire */ int used; /* reference count */ bool keyid_present; keyid_t keyid; int mac_len; #ifdef REFCLOCK bool network_packet; structpeer * recv_peer; #endif/* REFCLOCK */ };
structrecvbuf { recvbuf_t * link; /* next in list */ sockaddr_u recv_srcadr; sockaddr_u srcadr; /* where packet came from */ structnetendpt * dstadr;/* address pkt arrived on */ SOCKET fd; /* fd on which it was received */ l_fp recv_time; /* time of arrival */ void (*receiver)(struct recvbuf *); /* callback */ size_t recv_length; /* number of octets received */ union { structpktX_recv_pkt; uint8_t X_recv_buffer[RX_BUFF_SIZE]; } recv_space; #define recv_pkt recv_space.X_recv_pkt #define recv_buffer recv_space.X_recv_buffer structparsed_pktpkt;/* host-order copy of data from wire */ int used; /* reference count */ bool keyid_present; keyid_t keyid; int mac_len; #ifdef REFCLOCK bool network_packet; structpeer * recv_peer; #endif/* REFCLOCK */ };
这段代码定义了一个名为 write_variables 的函数,用于处理写入变量的操作。该函数接收两个参数:struct recvbuf *rbufp 和 int restrict_mask。函数的主要任务是从接收到的数据包中解析出变量名和值,并根据这些信息更新系统中的变量。
1 2 3 4 5 6 7 8 9 10
/* \* write_variables - write into variables. We only allow leap bit \* writing this way. */ /*ARGSUSED*/ static void write_variables( struct recvbuf *rbufp, int restrict_mask )
/* Scan the string in the packet until we hit comma or \* EoB. Register position of first '=' on the fly. */ for (tp = NULL, cp = reqpt; cp != reqend; ++cp) { if (*cp == '=' && tp == NULL) tp = cp; if (*cp == ',') break; }
这段代码的作用是从接收到的数据包中扫描一段字符串,直到遇到逗号(,)或字符串的末尾(EoB,End of Buffer)。同时,它还会记录第一个等号(=)的位置。这样的扫描主要用于解析控制消息中的变量名和值