Home | History | Annotate | Line # | Download | only in ntpq
libntpq.c revision 1.1.1.8
      1 /*	$NetBSD: libntpq.c,v 1.1.1.8 2017/04/13 19:17:32 christos Exp $	*/
      2 
      3 /*****************************************************************************
      4  *
      5  *  libntpq.c
      6  *
      7  *  This is the wrapper library for ntpq, the NTP query utility.
      8  *  This library reuses the sourcecode from ntpq and exports a number
      9  *  of useful functions in a library that can be linked against applications
     10  *  that need to query the status of a running ntpd. The whole
     11  *  communcation is based on mode 6 packets.
     12  *
     13  ****************************************************************************/
     14 #define LIBNTPQ_C
     15 #define NO_MAIN_ALLOWED 1
     16 /* #define BUILD_AS_LIB		Already provided by the Makefile */
     17 
     18 #include "ntpq.c"
     19 #include "libntpq.h"
     20 
     21 /* Function Prototypes */
     22 
     23 
     24 const char *Version = "libntpq 0.3beta";
     25 
     26 /* global variables used for holding snapshots of data */
     27 char peervars[NTPQ_BUFLEN];
     28 int peervarlen = 0;
     29 associd_t peervar_assoc = 0;
     30 char clockvars[NTPQ_BUFLEN];
     31 int clockvarlen = 0;
     32 int clockvar_assoc = 0;
     33 char sysvars[NTPQ_BUFLEN];
     34 int sysvarlen = 0;
     35 char *ntpq_resultbuffer[NTPQ_BUFLEN];
     36 unsigned short ntpq_associations[MAXASSOC];
     37 struct ntpq_varlist ntpq_varlist[MAXLIST];
     38 
     39 /*****************************************************************************
     40  *
     41  *  ntpq_stripquotes
     42  *
     43  *  Parses a given character buffer srcbuf and removes all quoted
     44  *  characters. The resulting string is copied to the specified
     45  *  resultbuf character buffer.  E.g. \" will be translated into "
     46  *
     47  ****************************************************************************
     48  * Parameters:
     49  *	resultbuf	char*	The resulting string without quoted
     50  *				characters
     51  *	srcbuf		char*	The buffer holding the original string
     52  *	datalen		int	The number of bytes stored in srcbuf
     53  *	maxlen		int	Max. number of bytes for resultbuf
     54  *
     55  * Returns:
     56  *	int		number of chars that have been copied to
     57  *			resultbuf
     58  ****************************************************************************/
     59 
     60 int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen )
     61 {
     62 	char* dst = resultbuf;
     63 	char* dep = resultbuf + maxlen - 1;
     64 	char* src = srcbuf;
     65 	char* sep = srcbuf + (datalen >= 0 ? datalen : 0);
     66 	int   esc = 0;
     67 	int   ch;
     68 
     69 	if (maxlen <= 0)
     70 		return 0;
     71 
     72 	while ((dst != dep) && (src != sep) && (ch = (u_char)*src++) != 0) {
     73 		if (esc) {
     74 			esc = 0;
     75 			switch (ch) {
     76 				/* skip and do not copy */
     77 				/* case '"':*/ /* quotes */
     78 			case 'n': /*newline*/
     79 			case 'r': /*carriage return*/
     80 			case 'g': /*bell*/
     81 			case 't': /*tab*/
     82 				continue;
     83 			default:
     84 				break;
     85 			}
     86 		} else {
     87 			switch (ch) {
     88 			case '\\':
     89 				esc = 1;
     90 			case '"':
     91 				continue;
     92 			default:
     93 				break;
     94 			}
     95 		}
     96 		*dst++ = (char)ch;
     97 	}
     98 	*dst = '\0';
     99 	return (int)(dst - resultbuf);
    100 }
    101 
    102 
    103 /*****************************************************************************
    104  *
    105  *  ntpq_getvar
    106  *
    107  *  This function parses a given buffer for a variable/value pair and
    108  *  copies the value of the requested variable into the specified
    109  *  varvalue buffer.
    110  *
    111  *  It returns the number of bytes copied or zero for an empty result
    112  *  (=no matching variable found or empty value)
    113  *
    114  ****************************************************************************
    115  * Parameters:
    116  *	resultbuf	char*	The resulting string without quoted
    117  *				characters
    118  *	datalen		size_t	The number of bytes stored in
    119  *							resultbuf
    120  *	varname		char*	Name of the required variable
    121  *	varvalue	char*	Where the value of the variable should
    122  *							be stored
    123  *	maxlen		size_t	Max. number of bytes for varvalue
    124  *
    125  * Returns:
    126  *	size_t		number of chars that have been copied to
    127  *			varvalue
    128  ****************************************************************************/
    129 
    130 size_t
    131 ntpq_getvar(
    132 	const char *	resultbuf,
    133 	size_t		datalen,
    134 	const char *	varname,
    135 	char *		varvalue,
    136 	size_t		maxlen)
    137 {
    138 	char *	name;
    139 	char *	value;
    140 	size_t	idatalen;
    141 
    142 	value = NULL;
    143 	idatalen = (int)datalen;
    144 
    145 	while (nextvar(&idatalen, &resultbuf, &name, &value)) {
    146 		if (strcmp(varname, name) == 0) {
    147 			ntpq_stripquotes(varvalue, value, strlen(value), maxlen);
    148 
    149 			return strlen(varvalue);
    150 		}
    151 	}
    152 
    153 	return 0;
    154 }
    155 
    156 
    157 /*****************************************************************************
    158  *
    159  *  ntpq_queryhost
    160  *
    161  *  Sends a mode 6 query packet to the current open host (see
    162  *  ntpq_openhost) and stores the requested variable set in the specified
    163  *  character buffer.
    164  *  It returns the number of bytes read or zero for an empty result
    165  *  (=no answer or empty value)
    166  *
    167  ****************************************************************************
    168  * Parameters:
    169  *      VARSET		u_short	Which variable set should be
    170  *				read (PEERVARS or CLOCKVARS)
    171  *	association	int	The association ID that should be read
    172  *				0 represents the ntpd instance itself
    173  *	resultbuf	char*	The resulting string without quoted
    174  *				characters
    175  *	maxlen		int	Max. number of bytes for varvalue
    176  *
    177  * Returns:
    178  *	int		number of bytes that have been copied to
    179  *			resultbuf
    180  *  			- OR -
    181  *			0 (zero) if no reply has been received or
    182  *			another failure occured
    183  ****************************************************************************/
    184 
    185 int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen)
    186 {
    187 	const char *datap;
    188 	int res;
    189 	size_t	dsize;
    190 	u_short	rstatus;
    191 
    192 	if ( numhosts > 0 )
    193 		res = doquery(VARSET,association,0,0, (char *)0, &rstatus, &dsize, &datap);
    194 	else
    195 		return 0;
    196 
    197 	if ( ( res != 0) || ( dsize == 0 ) ) /* no data */
    198 		return 0;
    199 
    200 	if ( dsize > maxlen)
    201 		dsize = maxlen;
    202 
    203 
    204 	/* fill result resultbuf */
    205 	memcpy(resultbuf, datap, dsize);
    206 
    207 	return dsize;
    208 }
    209 
    210 
    211 
    212 /*****************************************************************************
    213  *
    214  *  ntpq_openhost
    215  *
    216  *  Sets up a connection to the ntpd instance of a specified host. Note:
    217  *  There is no real "connection" established because NTP solely works
    218  *  based on UDP.
    219  *
    220  ****************************************************************************
    221  * Parameters:
    222  *	hostname	char*	Hostname/IP of the host running ntpd
    223  *	fam		int	Address Family (AF_INET, AF_INET6, or 0)
    224  *
    225  * Returns:
    226  *	int		1 if the host connection could be set up, i.e.
    227  *			name resolution was succesful and/or IP address
    228  *			has been validated
    229  *  			- OR -
    230  *			0 (zero) if a failure occured
    231  ****************************************************************************/
    232 
    233 int
    234 ntpq_openhost(
    235 	char *hostname,
    236 	int fam
    237 	)
    238 {
    239 	if ( openhost(hostname, fam) )
    240 	{
    241 		numhosts = 1;
    242 	} else {
    243 		numhosts = 0;
    244 	}
    245 
    246 	return numhosts;
    247 
    248 }
    249 
    250 
    251 /*****************************************************************************
    252  *
    253  *  ntpq_closehost
    254  *
    255  *  Cleans up a connection by closing the used socket. Should be called
    256  *  when no further queries are required for the currently used host.
    257  *
    258  ****************************************************************************
    259  * Parameters:
    260  *	- none -
    261  *
    262  * Returns:
    263  *	int		0 (zero) if no host has been opened before
    264  *			- OR -
    265  *			the resultcode from the closesocket function call
    266  ****************************************************************************/
    267 
    268 int ntpq_closehost(void)
    269 {
    270 	if ( numhosts )
    271 	 return closesocket(sockfd);
    272 
    273 	return 0;
    274 }
    275 
    276 
    277 /*****************************************************************************
    278  *
    279  *  ntpq_read_associations
    280  *
    281  *  This function queries the ntp host for its associations and returns the
    282  *  number of associations found.
    283  *
    284  *  It takes an u_short array as its first parameter, this array holds the
    285  *  IDs of the associations,
    286  *  the function will not write more entries than specified with the
    287  *  max_entries parameter.
    288  *
    289  *  However, if more than max_entries associations were found, the return
    290  *  value of this function will reflect the real number, even if not all
    291  *  associations have been stored in the array.
    292  *
    293  ****************************************************************************
    294  * Parameters:
    295  *	resultbuf	u_short*Array that should hold the list of
    296  *				association IDs
    297  *	maxentries	int	maximum number of association IDs that can
    298  *				be stored in resultbuf
    299  *
    300  * Returns:
    301  *	int		number of association IDs stored in resultbuf
    302  *  			- OR -
    303  *			0 (zero) if a failure occured or no association has
    304  *			been returned.
    305  ****************************************************************************/
    306 
    307  int  ntpq_read_associations ( u_short resultbuf[], int max_entries )
    308 {
    309     int i = 0;
    310 
    311     if (ntpq_dogetassoc()) {
    312 
    313         if(numassoc < max_entries)
    314           max_entries = numassoc;
    315 
    316         for (i=0;i<max_entries;i++)
    317             resultbuf[i] = assoc_cache[i].assid;
    318 
    319         return numassoc;
    320     }
    321 
    322     return 0;
    323 }
    324 
    325 
    326 
    327 
    328 /*****************************************************************************
    329  *
    330  *  ntpq_get_assocs
    331  *
    332  *  This function reads the associations of a previously selected (with
    333  *  ntpq_openhost) NTP host into its own (global) array and returns the
    334  *  number of associations found.
    335  *
    336  *  The obtained association IDs can be read by using the ntpq_get_assoc_id
    337  *  function.
    338  *
    339  ****************************************************************************
    340  * Parameters:
    341  *	- none -
    342  *
    343  * Returns:
    344  *	int		number of association IDs stored in resultbuf
    345  *  			- OR -
    346  *			0 (zero) if a failure occured or no association has
    347  *			been returned.
    348  ****************************************************************************/
    349 
    350  int  ntpq_get_assocs ( void )
    351 {
    352     return ntpq_read_associations( ntpq_associations, MAXASSOC );
    353 }
    354 
    355 
    356 /*****************************************************************************
    357  *
    358  *  ntpq_get_assoc_number
    359  *
    360  *  This function returns for a given Association ID the association number
    361  *  in the internal association array, which is filled by the ntpq_get_assocs
    362  *  function.
    363  *
    364  ****************************************************************************
    365  * Parameters:
    366  *	associd		int	requested associaton ID
    367  *
    368  * Returns:
    369  *	int		the number of the association array element that is
    370  *			representing the given association ID
    371  *  			- OR -
    372  *			-1 if a failure occured or no matching association
    373  * 			ID has been found
    374  ****************************************************************************/
    375 
    376 int ntpq_get_assoc_number ( associd_t associd )
    377 {
    378 	int i;
    379 
    380 	for (i=0;i<numassoc;i++) {
    381 		if (assoc_cache[i].assid == associd)
    382 			return i;
    383 	}
    384 
    385 	return -1;
    386 
    387 }
    388 
    389 
    390 /*****************************************************************************
    391  *
    392  *  ntpq_read_assoc_peervars
    393  *
    394  *  This function reads the peervars variable-set of a specified association
    395  *  from a NTP host and writes it to the result buffer specified, honoring
    396  *  the maxsize limit.
    397  *
    398  *  It returns the number of bytes written or 0 when the variable-set is
    399  *  empty or failed to read.
    400  *
    401  ****************************************************************************
    402  * Parameters:
    403  *	associd		int	requested associaton ID
    404  *	resultbuf	char*	character buffer where the variable set
    405  *				should be stored
    406  *	maxsize		int	the maximum number of bytes that can be
    407  *				written to resultbuf
    408  *
    409  * Returns:
    410  *	int		number of chars that have been copied to
    411  *			resultbuf
    412  *			- OR -
    413  *			0 (zero) if an error occured
    414  ****************************************************************************/
    415 
    416 int
    417 ntpq_read_assoc_peervars(
    418 	associd_t	associd,
    419 	char *		resultbuf,
    420 	int		maxsize
    421 	)
    422 {
    423 	const char *	datap;
    424 	int		res;
    425 	size_t		dsize;
    426 	u_short		rstatus;
    427 
    428 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
    429 		      &dsize, &datap);
    430 	if (res != 0)
    431 		return 0;
    432 	if (dsize <= 0) {
    433 		if (numhosts > 1)
    434 			fprintf(stderr, "server=%s ", currenthost);
    435 		fprintf(stderr,
    436 			"***No information returned for association %d\n",
    437 			associd);
    438 
    439 		return 0;
    440 	}
    441 	if (dsize > maxsize)
    442 		dsize = maxsize;
    443 	memcpy(resultbuf, datap, dsize);
    444 
    445 	return dsize;
    446 }
    447 
    448 
    449 
    450 
    451 /*****************************************************************************
    452  *
    453  *  ntpq_read_sysvars
    454  *
    455  *  This function reads the sysvars variable-set from a NTP host and writes it
    456  *  to the result buffer specified, honoring the maxsize limit.
    457  *
    458  *  It returns the number of bytes written or 0 when the variable-set is empty
    459  *  or could not be read.
    460  *
    461  ****************************************************************************
    462  * Parameters:
    463  *	resultbuf	char*	character buffer where the variable set
    464  *				should be stored
    465  *	maxsize		int	the maximum number of bytes that can be
    466  *				written to resultbuf
    467  *
    468  * Returns:
    469  *	int		number of chars that have been copied to
    470  *			resultbuf
    471  *			- OR -
    472  *			0 (zero) if an error occured
    473  ****************************************************************************/
    474 size_t
    475 ntpq_read_sysvars(
    476 	char *	resultbuf,
    477 	size_t	maxsize
    478 	)
    479 {
    480 	const char *	datap;
    481 	int		res;
    482 	size_t		dsize;
    483 	u_short		rstatus;
    484 
    485 	res = doquery(CTL_OP_READVAR, 0, 0, 0, NULL, &rstatus,
    486 		      &dsize, &datap);
    487 
    488 	if (res != 0)
    489 		return 0;
    490 
    491 	if (dsize == 0) {
    492 		if (numhosts > 1)
    493 			fprintf(stderr, "server=%s ", currenthost);
    494 		fprintf(stderr, "***No sysvar information returned\n");
    495 
    496 		return 0;
    497 	} else {
    498 		dsize = min(dsize, maxsize);
    499 		memcpy(resultbuf, datap, dsize);
    500 	}
    501 
    502 	return dsize;
    503 }
    504 
    505 
    506 /*****************************************************************************
    507  *  ntpq_get_assoc_allvars
    508  *
    509  *  With this function all association variables for the specified association
    510  *  ID can be requested from a NTP host. They are stored internally and can be
    511  *  read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
    512  *
    513  *  Basically this is only a combination of the ntpq_get_assoc_peervars and
    514  *  ntpq_get_assoc_clockvars functions.
    515  *
    516  *  It returns 1 if both variable-sets (peervars and clockvars) were
    517  *  received successfully. If one variable-set or both of them weren't
    518  *  received,
    519  *
    520  ****************************************************************************
    521  * Parameters:
    522  *	associd		int	requested associaton ID
    523  *
    524  * Returns:
    525  *	int		nonzero if at least one variable set could be read
    526  * 			- OR -
    527  *			0 (zero) if an error occured and both variable sets
    528  *			could not be read
    529  ****************************************************************************/
    530  int  ntpq_get_assoc_allvars( associd_t associd  )
    531 {
    532 	return ntpq_get_assoc_peervars ( associd ) &
    533 	       ntpq_get_assoc_clockvars( associd );
    534 }
    535 
    536 
    537 
    538 
    539 /*****************************************************************************
    540  *
    541  *  ntpq_get_sysvars
    542  *
    543  *  The system variables of a NTP host can be requested by using this function
    544  *  and afterwards using ntpq_get_sysvar to read the single variable values.
    545  *
    546  ****************************************************************************
    547  * Parameters:
    548  *	- none -
    549  *
    550  * Returns:
    551  *	int		nonzero if the variable set could be read
    552  * 			- OR -
    553  *			0 (zero) if an error occured and the sysvars
    554  *			could not be read
    555  ****************************************************************************/
    556 int
    557 ntpq_get_sysvars(void)
    558 {
    559 	sysvarlen = ntpq_read_sysvars(sysvars, sizeof(sysvars));
    560 	if (sysvarlen <= 0)
    561 		return 0;
    562 	else
    563 		return 1;
    564 }
    565 
    566 
    567 /*****************************************************************************
    568  *
    569  *  ntp_get_peervar
    570  *
    571  *  This function uses the variable-set which was read by using
    572  *  ntp_get_peervars and searches for a variable specified with varname. If
    573  *  such a variable exists, it writes its value into
    574  *  varvalue (maxlen specifies the size of this target buffer).
    575  *
    576  ****************************************************************************
    577  * Parameters:
    578  *	varname		char*	requested variable name
    579  *	varvalue	char*	the buffer where the value should go into
    580  *	maxlen		int	maximum number of bytes that can be copied to
    581  *				varvalue
    582  *
    583  * Returns:
    584  *	int		number of bytes copied to varvalue
    585  * 			- OR -
    586  *			0 (zero) if an error occured or the variable could
    587  *			not be found
    588  ****************************************************************************/
    589 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
    590 {
    591     return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
    592 }
    593 
    594 
    595 
    596 /*****************************************************************************
    597  *
    598  *  ntpq_get_assoc_peervars
    599  *
    600  *  This function requests the peer variables of the specified association
    601  *  from a NTP host. In order to access the variable values, the function
    602  *  ntpq_get_peervar must be used.
    603  *
    604  ****************************************************************************
    605  * Parameters:
    606  *	associd		int	requested associaton ID
    607  *
    608  * Returns:
    609  *	int		1 (one) if the peervars have been read
    610  * 			- OR -
    611  *			0 (zero) if an error occured and the variable set
    612  *			could not be read
    613  ****************************************************************************/
    614 int
    615 ntpq_get_assoc_peervars(
    616 	associd_t associd
    617 	)
    618 {
    619 	peervarlen = ntpq_read_assoc_peervars(associd, peervars,
    620 					      sizeof(peervars));
    621 	if (peervarlen <= 0) {
    622 		peervar_assoc = 0;
    623 
    624 		return 0;
    625 	}
    626 	peervar_assoc = associd;
    627 
    628 	return 1;
    629 }
    630 
    631 
    632 /*****************************************************************************
    633  *
    634  *  ntp_read_assoc_clockvars
    635  *
    636  *  This function reads the clockvars variable-set of a specified association
    637  *  from a NTP host and writes it to the result buffer specified, honoring
    638  *  the maxsize limit.
    639  *
    640  *  It returns the number of bytes written or 0 when the variable-set is
    641  *  empty or failed to read.
    642  *
    643  ****************************************************************************
    644  * Parameters:
    645  *	associd		int	requested associaton ID
    646  *	resultbuf	char*	character buffer where the variable set
    647  *				should be stored
    648  *	maxsize		int	the maximum number of bytes that can be
    649  *				written to resultbuf
    650  *
    651  * Returns:
    652  *	int		number of chars that have been copied to
    653  *			resultbuf
    654  *			- OR -
    655  *			0 (zero) if an error occured
    656  ****************************************************************************/
    657 
    658 int
    659 ntpq_read_assoc_clockvars(
    660 	associd_t	associd,
    661 	char *		resultbuf,
    662 	int		maxsize
    663 	)
    664 {
    665 	const char *datap;
    666 	int res;
    667 	size_t dsize;
    668 	u_short rstatus;
    669 
    670 	res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd,
    671 			       0, &rstatus, &dsize, &datap);
    672 	if (res != 0)
    673 		return 0;
    674 
    675 	if (dsize == 0) {
    676 		if (numhosts > 1) /* no information returned from server */
    677 			return 0;
    678 	} else {
    679 		if (dsize > maxsize)
    680 			dsize = maxsize;
    681 		memcpy(resultbuf, datap, dsize);
    682 	}
    683 
    684 	return dsize;
    685 }
    686 
    687 
    688 
    689 /*****************************************************************************
    690  *
    691  *  ntpq_get_assoc_clocktype
    692  *
    693  *  This function returns a clocktype value for a given association number
    694  *  (not ID!):
    695  *
    696  *  NTP_CLOCKTYPE_UNKNOWN   Unknown clock type
    697  *  NTP_CLOCKTYPE_BROADCAST Broadcast server
    698  *  NTP_CLOCKTYPE_LOCAL     Local clock
    699  *  NTP_CLOCKTYPE_UNICAST   Unicast server
    700  *  NTP_CLOCKTYPE_MULTICAST Multicast server
    701  *
    702  ****************************************************************************/
    703 int
    704 ntpq_get_assoc_clocktype(
    705 	int assoc_index
    706 	)
    707 {
    708 	associd_t	associd;
    709 	int		i;
    710 	int		rc;
    711 	sockaddr_u	dum_store;
    712 	char		dstadr[LENHOSTNAME];
    713 	char		resultbuf[NTPQ_BUFLEN];
    714 
    715 	if (assoc_index < 0 || assoc_index >= numassoc)
    716 		return -1;
    717 
    718 	associd = assoc_cache[assoc_index].assid;
    719 	if (associd == peervar_assoc) {
    720 		rc = ntpq_get_peervar("dstadr", dstadr, sizeof(dstadr));
    721 	} else {
    722 		i = ntpq_read_assoc_peervars(associd, resultbuf,
    723 					     sizeof(resultbuf));
    724 		if (i <= 0)
    725 			return -1;
    726 		rc = ntpq_getvar(resultbuf, i, "dstadr", dstadr,
    727 				 sizeof(dstadr));
    728 	}
    729 
    730 	if (0 != rc && decodenetnum(dstadr, &dum_store))
    731 		return ntpq_decodeaddrtype(&dum_store);
    732 
    733 	return -1;
    734 }
    735 
    736 
    737 
    738 /*****************************************************************************
    739  *
    740  *  ntpq_get_assoc_clockvars
    741  *
    742  *  With this function the clock variables of the specified association are
    743  *  requested from a NTP host. This makes only sense for associations with
    744  *  the type 'l' (Local Clock) and you should check this with
    745  *  ntpq_get_assoc_clocktype for each association, before you use this function
    746  *  on it.
    747  *
    748  ****************************************************************************
    749  * Parameters:
    750  *	associd		int	requested associaton ID
    751  *
    752  * Returns:
    753  *	int		1 (one) if the clockvars have been read
    754  * 			- OR -
    755  *			0 (zero) if an error occured and the variable set
    756  *			could not be read
    757  ****************************************************************************/
    758 int  ntpq_get_assoc_clockvars( associd_t associd )
    759 {
    760 	if (NTP_CLOCKTYPE_LOCAL != ntpq_get_assoc_clocktype(
    761 	    ntpq_get_assoc_number(associd)))
    762 		return 0;
    763 	clockvarlen = ntpq_read_assoc_clockvars( associd, clockvars,
    764 						 sizeof(clockvars) );
    765 	if ( clockvarlen <= 0 ) {
    766 		clockvar_assoc = 0;
    767 		return 0;
    768 	} else {
    769 		clockvar_assoc = associd;
    770 		return 1;
    771 	}
    772 }
    773 
    774 
    775