aboutsummaryrefslogtreecommitdiff
path: root/tests/cve.scm
blob: b69da0e1204c9c9ee20e77087718f8981ece369b (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015, 2016, 2019 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (test-cve)
  #:use-module (guix cve)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-19)
  #:use-module (srfi srfi-64))

(define %sample
  (search-path %load-path "tests/cve-sample.json"))

(define (vulnerability id packages)
  (make-struct/no-tail (@@ (guix cve) <vulnerability>) id packages))

(define %expected-vulnerabilities
  ;; What we should get when reading %SAMPLE.
  (list
   (vulnerability "CVE-2019-0001"
                  ;; Only the "a" CPE configurations are kept; the "o"
                  ;; configurations are discarded.
                  '(("junos" (or "18.21-s4" (or "18.21-s3" "18.2")))))
   (vulnerability "CVE-2019-0005"
                  '(("junos" (or "18.11" "18.1"))))
   ;; CVE-2019-0005 has no "a" configurations.
   (vulnerability "CVE-2019-14811"
                  '(("ghostscript" (< "9.28"))))
   (vulnerability "CVE-2019-17365"
                  '(("nix" (<= "2.3"))))
   (vulnerability "CVE-2019-1010180"
                  '(("gdb" _)))                   ;any version
   (vulnerability "CVE-2019-1010204"
                  '(("binutils" (and (>= "2.21") (<= "2.31.1")))
                    ("binutils_gold" (and (>= "1.11") (<= "1.16")))))
   ;; CVE-2019-18192 has no associated configurations.
   ))


(test-begin "cve")

(test-equal "json->cve-items"
  '("CVE-2019-0001"
    "CVE-2019-0005"
    "CVE-2019-14811"
    "CVE-2019-17365"
    "CVE-2019-1010180"
    "CVE-2019-1010204"
    "CVE-2019-18192")
  (map (compose cve-id cve-item-cve)
       (call-with-input-file %sample json->cve-items)))

(test-equal "cve-item-published-date"
  '(2019)
  (delete-duplicates
   (map (compose date-year cve-item-published-date)
        (call-with-input-file %sample json->cve-items))))

(test-equal "json->vulnerabilities"
  %expected-vulnerabilities
  (call-with-input-file %sample json->vulnerabilities))

(test-equal "vulnerabilities->lookup-proc"
  (list (list (third %expected-vulnerabilities))  ;ghostscript
        (list (third %expected-vulnerabilities))
        '()

        (list (fifth %expected-vulnerabilities))  ;gdb
        (list (fifth %expected-vulnerabilities))

        (list (fourth %expected-vulnerabilities)) ;nix
        '()

        (list (sixth %expected-vulnerabilities))  ;binutils
        '()
        (list (sixth %expected-vulnerabilities))
        '())
  (let* ((vulns  (call-with-input-file %sample json->vulnerabilities))
         (lookup (vulnerabilities->lookup-proc vulns)))
    (list (lookup "ghostscript")
          (lookup "ghostscript" "9.27")
          (lookup "ghostscript" "9.28")
          (lookup "gdb")
          (lookup "gdb" "42.0")
          (lookup "nix")
          (lookup "nix" "2.4")
          (lookup "binutils" "2.31.1")
          (lookup "binutils" "2.10")
          (lookup "binutils_gold" "1.11")
          (lookup "binutils" "2.32"))))

(test-end "cve")
'>-ldns_pkt *
-receive_and_print(int so) {
- uint8_t inbuf[INBUF_SIZE];
- ssize_t nb;
- ldns_status status;
- ldns_pkt *query_pkt;
-
- nb = recvfrom(so, inbuf, INBUF_SIZE, 0, &paddr, &plen);
- if (nb == -1) {
- if (errno == EINTR || errno == EAGAIN)
- return NULL;
- else
- err(EXIT_FAILURE, "recvfrom");
- }
-
- status = ldns_wire2pkt(&query_pkt, inbuf, (size_t)nb);
- if (status != LDNS_STATUS_OK) {
- warnx("bad packet: %s", ldns_get_errorstr_by_id(status));
- return NULL;
- } else {
- puts("received packet:");
- printpacket(query_pkt);
- }
-
- return query_pkt;
-}
-
-int
-send_response(int so, const char *hostname, ldns_pkt *respkt, uint16_t id)
-{
- size_t answer_size;
- ldns_status status;
- uint8_t *outbuf = NULL;
- int rv = 1;
-
- if (hostname == NULL || respkt == NULL) {
- warnx("send_response: invalid parameters");
- return (0);
- }
-
- ldns_pkt_set_id(respkt, id);
- status = ldns_pkt2wire(&outbuf, respkt, &answer_size);
- if (status != LDNS_STATUS_OK)
- warnx("can't create answer: %s",
- ldns_get_errorstr_by_id(status));
- else {
- puts("response packet:");
- printpacket(respkt);
-
- if (sendto(so, outbuf, answer_size, 0, &paddr, plen) == -1)
- warn("send_response: sendto");
- else {
- rv = 0;
-
- printf("send_response: resolved %s", hostname);
- }
- }
-
- if (outbuf)
- LDNS_FREE(outbuf);
-
- return (rv);
-}
-
-char *
-hostnamefrompkt(ldns_pkt *pkt, ldns_rr **qrr)
-{
- ldns_rr *query_rr;
- ldns_buffer *out = NULL;
- ldns_rdf *rdf;
- char *ret = NULL;
-
- if (pkt == NULL)
- return (NULL);
-
- query_rr = ldns_rr_list_rr(ldns_pkt_question(pkt), 0);
- if (query_rr == NULL) {
- warnx("hostnamefrompkt invalid parameters");
- goto done;
- }
-
- out = ldns_buffer_new(LDNS_MAX_DOMAINLEN);
- if (out == NULL) {
- warnx("no memory for out buffer");
- goto done;
- }
-
- rdf = ldns_rr_owner(query_rr);
- if (ldns_rdf2buffer_str_dname(out, rdf) != LDNS_STATUS_OK) {
- warnx("can't get hostname");
- goto done;
- }
-
- ret = strdup((char *)ldns_buffer_begin(out));
- if (ret == NULL) {
- warn("no memory for hostname");
- goto done;
- }
-
- if (qrr)
- *qrr = query_rr;
-done:
- if (out)
- ldns_buffer_free(out);
-
- return (ret);
-}
-
-int
-respond_query(int so, const char *hostname, const char *ipaddr,
- ldns_rr *query_rr, uint16_t id)
-{
- ldns_status status;
- ldns_rr_list *answer_an = NULL;
- ldns_rr_list *answer_ns = NULL;
- ldns_rr_list *answer_ad = NULL;
- ldns_rr_list *answer_qr = NULL;
- ldns_pkt *answer_pkt = NULL;
- ldns_rr *myrr = NULL, *myaurr = NULL, *myasrr = NULL;
- ldns_rdf *prev = NULL;
- char buf[MAXLINE * 2];
- uint8_t *outbuf = NULL;
- int rv = 1;
-
- /* answer section */
- answer_an = ldns_rr_list_new();
- if (answer_an == NULL)
- goto unwind;
-
- /* authority section */
- answer_ns = ldns_rr_list_new();
- if (answer_ns == NULL)
- goto unwind;
-
- /* if we have an ip spoof it there */
- if (ipaddr) {
- /* an */
- snprintf(buf, sizeof buf, "%s\t%d\tIN\tA\t%s",
- hostname, 259200, ipaddr);
- status = ldns_rr_new_frm_str(&myrr, buf, 0, NULL, &prev);
- if (status != LDNS_STATUS_OK) {
- fprintf(stderr, "can't create answer section: %s\n",
- ldns_get_errorstr_by_id(status));
- goto unwind;
- }
- ldns_rr_list_push_rr(answer_an, myrr);
- ldns_rdf_deep_free(prev);
- prev = NULL;
-
- /* ns */
- snprintf(buf, sizeof buf, "%s\t%d\tIN\tNS\t%s.",
- hostname, 259200, "localhost");
- status = ldns_rr_new_frm_str(&myaurr, buf, 0, NULL, &prev);
- if (status != LDNS_STATUS_OK) {
- fprintf(stderr, "can't create authority section: %s\n",
- ldns_get_errorstr_by_id(status));
- goto unwind;
- }
- ldns_rr_list_push_rr(answer_ns, myaurr);
- ldns_rdf_deep_free(prev);
- prev = NULL;
- } else {
- snprintf(buf, sizeof buf, "%s\t3600\tIN\tSOA\t%s root.%s %s",
- hostname,
- hostname,
- hostname,
- "2 3600 900 3600000 3600");
- status = ldns_rr_new_frm_str(&myaurr, buf, 0, NULL, &prev);
- if (status != LDNS_STATUS_OK) {
- fprintf(stderr, "can't create authority section: %s\n",
- ldns_get_errorstr_by_id(status));
- goto unwind;
- }
- ldns_rr_list_push_rr(answer_ns, myaurr);
- ldns_rdf_deep_free(prev);
- prev = NULL;
- }
-
- /* question section */
- answer_qr = ldns_rr_list_new();
- if (answer_qr == NULL)
- goto unwind;
- ldns_rr_list_push_rr(answer_qr, ldns_rr_clone(query_rr));
-
- /* additional section */
- answer_ad = ldns_rr_list_new();
- if (answer_ad == NULL)
- goto unwind;
- if (ipaddr) {
- snprintf(buf, sizeof buf, "%s\t%d\tIN\tA\t%s",
- "localhost",
- 259200,
- "127.0.0.1");
- status = ldns_rr_new_frm_str(&myasrr, buf, 0, NULL, &prev);
- if (status != LDNS_STATUS_OK) {
- fprintf(stderr, "can't create additional section: %s\n",
- ldns_get_errorstr_by_id(status));
- goto unwind;
- }
- ldns_rr_list_push_rr(answer_ad, myasrr);
- ldns_rdf_deep_free(prev);
- prev = NULL;
-
- /* V6 */
- snprintf(buf, sizeof buf, "%s\t%d\tIN\tAAAA\t%s",
- "localhost",
- 259200,
- "::1");
- status = ldns_rr_new_frm_str(&myasrr, buf, 0, NULL, &prev);
- if (status != LDNS_STATUS_OK) {
- fprintf(stderr, "can't create additional section: %s\n",
- ldns_get_errorstr_by_id(status));
- goto unwind;
- }
- ldns_rr_list_push_rr(answer_ad, myasrr);
- ldns_rdf_deep_free(prev);
- prev = NULL;
- }
-
- /* actual packet */
- answer_pkt = ldns_pkt_new();
- if (answer_pkt == NULL)
- goto unwind;
-
- ldns_pkt_set_qr(answer_pkt, 1);
- ldns_pkt_set_aa(answer_pkt, 1);
- if (ipaddr == NULL)
- ldns_pkt_set_rcode(answer_pkt, LDNS_RCODE_NXDOMAIN);
-
- ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_QUESTION, answer_qr);
- ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ANSWER, answer_an);
- ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_AUTHORITY, answer_ns);
- ldns_pkt_push_rr_list(answer_pkt, LDNS_SECTION_ADDITIONAL, answer_ad);
-
- /* reply to caller */
- if (send_response(so, hostname, answer_pkt, id))
- warnx("send_response failed");
-
-unwind:
- if (answer_pkt)
- ldns_pkt_free(answer_pkt);
- if (outbuf)
- LDNS_FREE(outbuf);
- if (answer_qr)
- ldns_rr_list_free(answer_qr);
- if (answer_an)
- ldns_rr_list_free(answer_an);
- if (answer_ns)
- ldns_rr_list_free(answer_ns);
- if (answer_ad)
- ldns_rr_list_free(answer_ad);
-
- return (rv);
-}